7

I have a hard time understanding when to use the asterisk operator for dereferencing and when can I omit it.

fn main() { a(); b(); c(); d(); }

fn a() {
    let v = 1;
    let x = &v;
    println!("a {}", *x);
    println!("a {}", 1 + *x);
}

fn b() {
    let v = 1;
    let x = &v;
    println!("b {}", x);
    println!("b {}", 1 + x);
}

fn c() {
    let mut v = 1;
    let mut x = &mut v;
    println!("c {}", *x);
    println!("c {}", 1 + *x);
}

fn d() {
    let mut v = 1;
    let mut x = &mut v;
    println!("d {}", x);
    println!("d {}", 1 + x); // error
}

The above code sample almost compiles except the last statement where I add one to the the mutable reference x. There I get this error:

the trait bound `_: std::ops::Add<&mut _>` is not satisfied [E0277]

Anywhere else both asterisk and non-asterisk versions are valid and give expected results.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Midiparse
  • 4,701
  • 7
  • 28
  • 48

1 Answers1

5

You can only add types for which the operator is defined by implementing the Add trait. In both examples where you do 1 + *x, the type of *x is i32 and indeed i32 + i32 is defined. For convenience there is also an implementation of i32 + &i32 (and &i32 + i32 and &i32 + &i32) which makes b work, but this is just for the specific case of one immutable reference, it doesn't extend to, say &&i32 or &mut i32. That's why d does not work.

  • I see. What do you suggest to use where both forms are allowed and yield the same results? Should I stick to the asterisk everytime, or should I take advantage of the convenience implementations? – Midiparse Jul 02 '16 at 18:17
  • You should use them, that's why they exit. Superfluous dereferencing doesn't clarify the code, it just adds line noise. –  Jul 02 '16 at 18:30
  • Should the third sentence be "For convenience... which makes **`b`** work..." because `b` is the function with the immutable reference that is not explicitly dereferenced? – cspin Nov 27 '16 at 21:52