This will fail:
fn ppv(arr: &mut Vec<i32>) {
if arr.len() <= 0 {
return;
}
let mut pp: i32 = 0;
for &mut val in arr {
if val == pp {
pp = val;
}
}
println!("arr is {:?}", &arr);
}
But this will pass:
fn ppv(arr: &mut Vec<i32>) {
if arr.len() <= 0{
return;
}
let mut pp: i32 = 0;
for &mut val in arr.into_iter() {
if val == pp {
pp = val;
}
}
println!("arr is {:?}", &arr);
}
when I compile the first one, it failed:
error[E0382]: borrow of moved value: `arr`
--> src/main.rs:12:29
|
2 | fn ppv(arr: &mut Vec<i32>) {
| --- move occurs because `arr` has type `&mut Vec<i32>`, which does not implement the `Copy` trait
...
7 | for &mut val in arr {
| --- `arr` moved due to this implicit call to `.into_iter()`
...
12 | println!("arr is {:?}", &arr);
| ^^^^ value borrowed here after move
|
Why is that? Is it interpreting it differently?
First case will implicit call into_iter()
, it failed, when I call into_iter()
, it passed. What happened?
I believe the difference is in reborrow, performed in the latter case, but not the former.
Mutable references are normally not Copy
. This is by design, as copying a mutable reference would allow mutable aliasing. But then, the question is how does this work:
fn foo(v: &mut Vec<i32>) {
v.push(1); // equivalent to Vec::push(v, 1)
v.push(2); // equivalent to Vec::push(v, 2)
}
If the first call to push()
receives v
, which is not Copy
, then the second call to push()
should fail to compile with "use of moved value". And yet it compiles, as do the desugared versions.
The reason it compiles is that the compiler automatically performs reborrowing, replacing v
with &mut *v
. In other words. This transformation is done both on the receiver (self
) and the function arguments:
// v is &mut Vec<i32>
v.push(1); // treated as (&mut *v).push(1)
Vec::push(v, 2); // treated as Vec::push(&mut *v, 2)
The reborrowed form compiles because it is allowed to create a temporary mutable reference based on an existing mutable reference (e.g. through &mut r.some_field
where r
is &mut SomeStruct
), as long as the temporary reference lives shorter than the original, and you don't use the original reference while the temporary one is live.
You typically notice reborrowing only in the rare cases when it fails. This answer describes such case with serde, where reborrowing failed due to use of generics.
To get back to the original example, your for
loop is another example of reborrow failing to happen. Given a mutable reference arr
, the difference between for &mut val in arr
and for &mut val in arr.into_iter()
is that the explicit call to into_iter()
is treated as (&mut *arr).into_iter()
and thereby allows continued use of arr
after the loop. The naked for
doesn't do so, and the arr
object is lost.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With