35

I'm new to Rust and I don't understand the following piece of code:

let mut x = 5;
{
    let y = &mut x;
    *y += 1;
}
println!("{}", x);

Explanation from the Rust site:

You'll also notice we added an asterisk (*) in front of y, making it *y, this is because y is a &mut reference. You'll need to use astrisks [sic] to access the contents of a reference as well.

If *y is a reference, why does the following code work

fn main() {
    let mut x = 5;
    {
        let y = &mut x;
        println!("{}", y);
    }
}

I know I'm not modifying the value here, but what is the difference and why would y += 1; not work?

kmdreko
  • 42,554
  • 6
  • 57
  • 106
Pepernoot
  • 3,409
  • 3
  • 21
  • 46
  • 4
    Possibly worth a read: [Auto-dereferencing](http://stackoverflow.com/documentation/rust/2574/auto-dereferencing#t=201611101618367290575) (from the Rust documentation section on this site), which explains some of the cases where `*` is not needed. – Aurora0001 Nov 10 '16 at 16:19
  • 1
    The link is broken. – Martin Marconcini Jan 10 '22 at 13:37
  • Found another link may be useful: https://stackoverflow.com/questions/28519997/what-are-rusts-exact-auto-dereferencing-rules – CodyChan Jan 11 '22 at 00:00
  • Related: [What do the ampersand '&' and star '*' symbols mean in Rust?](/q/36335342/2189130) – kmdreko Oct 01 '22 at 15:41

1 Answers1

36

If *y is a reference

*y is not a reference. y is a reference; *y dereferences y, allowing you access to the referred-to value.

what is the difference [between += and println!]

println! is a macro that automatically references the arguments given to it. In addition, the Display trait (used via {} in the format string) is implemented for all references to types that themselves implement Display (impl<'a, T> Display for &'a T where T: Display + ?Sized).

Thus, println!("{}", y); is actually printing out a reference to a reference to a value. Those intermediate references are automatically dereferenced due to the implementation of Display.

+=, on the other hand, is implemented via the AddAssign trait. The standard library only implements adding an integer type to itself (impl AddAssign<i32> for i32). That means that you have to add an appropriate level of dereferencing in order to get both sides to an integer.

Community
  • 1
  • 1
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
  • Would it be possible to add an implementation of `AddAssign` for `&mut i32`? It seems to be like this would be quite logical, but maybe I'm missing a pitfall. – Matthieu M. Nov 10 '16 at 16:28
  • @MatthieuM. I do believe it's *possible*, and the `Add` trait does have some precedent. I have a feeling that there's some good reason, but the [RFC lists it under unresolved questions](https://github.com/rust-lang/rfcs/blob/master/text/0953-op-assign.md#unresolved-questions). Also you might be interested in [this](https://github.com/rust-lang/rust/pull/36380) ^_^ – Shepmaster Nov 10 '16 at 16:34
  • Ah! Didn't even think to check whether the quote was exact or not :P – Matthieu M. Nov 10 '16 at 18:11
  • @Shepmaster https://github.com/rust-lang/rust/pull/36380 is pointing to the PR which fixes typo in word. Why this could be interesting? – Slava Semushin Nov 11 '16 at 11:05
  • @SlavaSemushin you'll note that I directed that comment at Matthieu M., who correctly realized that the quote in OP contained a mistyped word. However, the original source that the quote was from contained the typo (thus why I added `[sic]` to the quote) and then I pointed out to them that the typo has been fixed in upstream, just not published yet. – Shepmaster Nov 11 '16 at 14:29