3

I am confused by this example.

    let mut numbers: Vec<i32> = vec![1,2,3,4];
    for x in numbers.iter() {
        println!("Number: {}", x);
    }

    // Try to double the values in the vector.
    for x in numbers.iter_mut() {
        *x *= 2;
    }

when I tried x *= 2;, the compiler complains cannot use '*=' on type '&mut i32' but isn't x just a mut i32? why it is a &mut i32? if it is a &mut i32 why I dont need to print it as println!("Number: {}", *x)?

E_net4
  • 27,810
  • 13
  • 101
  • 139
user1722361
  • 377
  • 1
  • 4
  • 14
  • 1
    When you look at the [documentation of `iter_mut`](https://doc.rust-lang.org/std/primitive.slice.html#method.iter_mut), there's a bold ⓘ next to the function declaration. Hover it to see the type of the items returned by the iterator (IMO this should be explicitly written in the description of the function). – Denys Séguret Jun 16 '21 at 08:53

2 Answers2

4

but isn't x just a mut i32?

Nope, iter_mut returns an IterMut item, which implements Iterator<Item=&mut T>, so you are actually getting an &mut i32

why don't I need to print it as println!("Number: {}", *x)?

Because Display is implemented for &mut T by delegating to T, so println!("{}", x) and println!("{}", *x) print the same thing. For more information, see how println! works

trent
  • 25,033
  • 7
  • 51
  • 90
Netwave
  • 40,134
  • 6
  • 50
  • 93
  • 2
    Pretty sure that's not quite true. `println!` strips any number of references and also performs some tricks so that non-`Copy` types are not moved into it (like they would into a function). So the reason is macro magic rather than trait method receiver types. – Lukas Kalbertodt Jun 16 '21 at 07:36
  • Aaah, so I'm wrong then @LukasKalbertodt, Thanks! let me investigate println! to see it :) – Netwave Jun 16 '21 at 07:39
  • 1
    Yes, this question is about that behavior: https://stackoverflow.com/questions/30450399/does-println-borrow-or-own-the-variable – Nicolas Dusart Jun 16 '21 at 07:40
-2

if x is a &mut i32 why don't I need to print it as println!("Number: {}", *x)?

Good question!

The answer is because, when you use the println!() macro, references are automatically dereferenced. So the following lines are functionally equivalent:

println!("Number: {}", x);  // x is a reference
println!("Number: {}", *x);

In fact, all these lines (the ones after the declaration) are equivalent, too:

let x = 5;
println!("{}", x);   // prints: 5
println!("{}", &x);   // prints: 5
println!("{}", &&x);   // prints: 5
println!("{}", &&&x);   // prints: 5
println!("{}", &&&&x);   // prints: 5
println!("{}", &&&&&x);   // prints: 5
println!("{}", &&&&&&x);   // prints: 5

So it doesn't matter how many times I reference a reference of a reference, because when I use the println!() macro all my references will be glady dereferenced for me.

This is convenient behavior when using println!(), but it can cause some confusion if you don't realize you're using a reference.

EDIT: Changed wording so that it no longer explicitly says that it's the println!() macro that is doing the dereferencing behavior.

J-L
  • 1,786
  • 10
  • 13
  • `println!` does not automatically dereference anything. This behavior is due to the implementation of `Display` for `&T` (which just delegates to `T`'s implementation). `println!` does automatically *borrow* its arguments (which is why you can pass a non-`Copy` value without moving it) but that is not especially relevant here. – trent Jun 17 '21 at 11:38
  • @trentcl, I changed the wording of my post so that it no longer explicitly says that it's the `println!()` macro that is doing the dereferencing behavior. – J-L Jun 17 '21 at 16:13
  • The post is still misleading. There are two ways in which Rust *does* automatically dereference things for you (deref coercions and autoderef, both of which are covered in other SO questions). What's happening here is neither of those things. There's no dereferencing in this code, and the dereference that does happen (buried in `impl Display for &T where T: Display`) is not "automatic". – trent Jun 17 '21 at 22:16