fn main() {
let mut a = vec!["a", "b", "c"];
let b = &mut a;
for x in b {
*x = "d";
}
println!("{:?}", b);
}
This code gives the error, like below.
error[E0382]: use of moved value: `b`
--> src/main.rs:7:22
|
4 | for x in b {
| - value moved here
...
7 | println!("{:?}", b);
| ^ value used here after move
|
= note: move occurs because `b` has type `&mut std::vec::Vec<&str>`, which does not implement the `Copy` trait
However, this code works.
fn main() {
let mut a = vec!["a", "b", "c"];
let b = &mut a;
for x in b.into_iter() {
*x = "d";
}
println!("{:?}", b);
}
So, what the difference is? In some references, what rust's "for" syntax do for types which aren't Iterator seems to be just calling into_iter() (if implemented).
The Iterator doc has all the details, but the gist here is that the for loop calls IntoIterator::into_iter(expression), so the effect you see is due to the differences in method lookup and ownership when comparing:
The details I can see at least is that (1) is a function call and (2) is a method call.
Function call
a. No autoref; if we pass A but &A is expected, no adjustment is done, and instead it is a type error
b. This function is generic, so we have no clear expected type, so coercions are also not used here
c. One adjustment is done with function calls: reborrowing. But it's not done here, because the function is generic with a "by-value" parameter. (This part I find a bit confusing)
Method call
a. Method calls do adjustments like autoref or dereference. If we call into_iter() on an A, it will adjust it to *A, &A, &mut A or etc to what fits the method's receiver. Part of this adjustment is to reborrow instead of consume a mutable reference. This is what we see in the original question.
b. Adjustments include going through the Deref trait as well, if the first type does not have a matching method.
c. Adjustments include going through unsizing (finding slice methods for an array and such things). You can see that for [0; 128].into_iter().