I am going through the "Rust Book" website in order to learn the language for an upcoming job interview. In the chapter on vectors, there are two code samples:
fn main() {
let v = vec![100, 32, 57];
for i in &v {
println!("{}", i);
}
}
and:
fn main() {
let mut v = vec![100, 32, 57];
for i in &mut v {
*i = 50;
}
}
Now I am wondering, why is it that for the first sample, when we pass the reference to the vector element i into:
println!("{}", i);
but in the sample where we add 50 to each element of the vector, we have to dereference the element with * before we add to the 50?
Why don't/can't we do the following:
fn main() {
let v = vec![100, 32, 57];
for i in &v {
println!("{}", *i); // why don't we have to dereference before we pass to println!?
}
}
or:
fn main() {
let mut v = vec![100, 32, 57];
for i in &mut v {
i = 50; // why can't we just add directly to the reference like this?
}
}
I must have misunderstood what I read, but I thought Rust was able to discern when you need to dereference or not automatically. I guess I don't understand why we need to dereference (or not dereference) in the two samples. The two examples I provided are commented with the specific bits of code I am wondering about.
CodePudding user response:
I think the easiest way to look at this is that the second example is the "normal" one.
fn main() {
let mut v = vec![100, 32, 57];
for i in &mut v {
*i = 50;
}
}
i
is a &mut i32
(only i32
because there's nothing from which to infer any other integer type), so to assign to it you need to dereference to a mut i32
.
The println!
example is the one doing some "magic". println!
will format types whether they're passed by value or by reference. This is very handy, you wouldn't want it to (for example) clone every string you want to print out but then use later in the application.
Edit:
For completeness, this "magic" isn't really magic at all, but nice use of language features. println!
(like every other standard macro that does formatting, like panic!
and format!
) uses the formatting machinery from the standard library. This can work with any type that implements the Display
trait (or the Debug
trait if you use {:?}
). And Display
has a blanket impl for all references of things the implement Display
(Debug
also does this):
impl<'_, T> Display for &'_ T where
T: Display ?Sized,
{ /* ... */ }
So anything you can format with a value, you can also format with a reference.