Confusions between &T and &mut T in terms of numeric std::ops traits


#1

I came across some snippets about “numeric” operations +, & etc (https://doc.rust-lang.org/nightly/std/ops/index.html) and find out Rust has the weird treatment of the borrowed reference type.

For example, the code below runs correctly, but the commented two statements are disallowed.

fn main() {
    let mut arr = [1u8, 2, 3, 4];
    {
        let pos: &u8 = unsafe { arr.get_unchecked(2) };
        let v: u8 = pos + &1u8;
        let w: u8 = &2u8 + pos;
        println!("v={}, w={}", v, w);
    }
    {
        let pos: &mut u8 = unsafe { arr.get_unchecked_mut(2) };
        // let v = pos + 1u8;
        // *pos += &1u8;
        let v: u8 = *pos + &1u8;
        let w: u8 = &2u8 + *pos;
        println!("v={}, w={}", v, w);
    }
}

Also here https://play.rust-lang.org/?gist=123227c671b7875adac433d1a76184ee&version=nightly

My question is that why Rust allows operations between "&T op T", "&T op &T“, and "T op &T" (and the resulting type is T) where T is a primitive numeric type, but doesn’t allow "&mut T op T” etc.
This to me seems rather unintuitive and I would expect that Rust requires programmers to be more explicit. Is there a particular reason that forces Rust to behave like this?


#2

Looks like nobody implemented Add for a &mut {integer}, probably because it’s extra noise for no real gain: mutable refs aren’t as common as values or immutable refs for these types, and the “workaround” of deref’ing is simple enough. But maybe there’s a more principled reason.


#3
fn increment_key(&mut self, key: K) {
    let count = self.map.entry(key).or_insert(0);
    count + 1;
}

Edit: Actually, you can still just as easily write *count + 1 so _/o\_


#4

Do you mean something like this?

use std::collections::HashMap;
fn increment_key(key: u8) {
    let mut map = HashMap::new();
    map.insert(1u8, 1u8);
    let count = map.entry(key).or_insert(0);
    let v = count + 1u8;
    println!("{}", v);
}

It cannot compile.


#5

Actually I think “&T op T” etc also bring no gain, but just surprise to me :frowning:


#6

Maybe. Immutable references feature heavily in Rust though. Say iterating over an immutable slice. You can of course dereference and/or pattern match away the references but it becomes a bit boilerplate-y at times, particularly with iterator chains. That’s why things like https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.cloned exist too.