3

I have

fn plus_one(x: &i32) -> i32 {
    x + 1
}

fn plus_one_star(x: &i32) -> i32 {
    *x + 1
}

fn plus_one_mut(x: &mut i32) -> i32 {
    x + 1
}

fn plus_one_mut_star(x: &mut i32) -> i32 {
    *x + 1
}

fn main() {
    let a: i32 = 5;
    let mut b: i32 = 5;

    println!("{:?}", plus_one(&a));
    println!("{:?}", plus_one_star(&a));
    println!("{:?}", plus_one_mut(&mut b));
    println!("{:?}", plus_one_mut_star(&mut b));
    // I expect all to print '6' as I never actually mutate b
}

The third function, plus_one_mut, fails to compile with: error[E0369]: binary operation `+` cannot be applied to type '&mut i32'

Why does this function with the mutable reference fail to compile?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
turbulencetoo
  • 3,447
  • 1
  • 27
  • 50

1 Answers1

5

As the error message says:

binary operation + cannot be applied to type '&mut i32'

That's because it's not implemented. Reviewing the documentation for i32, you will see these implementations of Add:

  • impl Add<i32> for i32
  • impl<'a> Add<i32> for &'a i32
  • impl<'a> Add<&'a i32> for i32
  • impl<'a, 'b> Add<&'a i32> for &'b i32

You need to dereference &mut i32 to get to i32, which does have an Add implementation.

Why does it not have that implementation? I'm not sure. Perhaps you can submit a PR to Rust to add it... Personally, I've can't recall ever needing it. Usually if you have a &mut T it's because you want to update it, so you would have something like *foo += 1.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
  • 2
    the strange thing is that `x.add(1)` works in all cases though... In that case probably coercion kicks in? – Paolo Falabella Jan 23 '17 at 14:43
  • @PaoloFalabella I'm not sure when *coercion* is the right term; but yes, I'd assume that [automatic dereferencing](http://stackoverflow.com/q/28519997/155423) is coming into play there. – Shepmaster Jan 23 '17 at 15:23
  • So in this case an `&T` is behaving just like a `T`. In general though should I be dereferencing all my immutable references before using them? Or is it exceedingly common to implement most all of `T`s methods for `&T`? – turbulencetoo Jan 24 '17 at 16:47
  • @turbulencetoo I'm not sure I follow you. If you have a value, you can call *methods* of that type that accept `&self` or `self` with no ceremony. Whether or not you implement the method as taking `self` or `&self` boils down to what the function needs to do. I would wager that a majority of methods take `&self` because they don't need the power granted by `&mut self` or `self`. I find it reasonably rare to have to add an explicit `*` and generally wait until the compiler tells me to add it. – Shepmaster Jan 24 '17 at 16:52