I am trying to better understand move semantics and the behavior of Copy
types in Rust.
I know that &mut
T is not Copy
, as explained here, because copying &mut T
would create an aliased mutable reference. But then I do not understand the behavior of the following program:
fn my_ref_mut(the_ref_mut: &mut Vec<i32>) {
println!("{:?}", the_ref_mut);
}
fn main() {
let mut v: Vec<i32> = Vec::new();
let r: &mut Vec<i32> = &mut v;
my_ref_mut(r);
my_ref_mut(r); // Should not this be an `use after move` error?
}
I would have expected the program above not to compile because of an E0382: use of moved value
error. The r
variable behaves as if it is Copy
. I have tried to better understand the situation with the following program. It gives two different compilation errors, depending on whether the types are explicitly specified (for me to be sure I get the expected types):
fn my_ref_mut(the_ref_mut: &mut Vec<i32>) {
println!("{:?}", the_ref_mut);
}
fn my_ref(the_ref: &Vec<i32>) {
println!("{:?}", the_ref);
}
fn main() {
let mut v: Vec<i32> = Vec::new();
{
let r: &mut Vec<i32> = &mut v;
my_ref_mut(r);
my_ref_mut(r);
}
{
let r1: &mut Vec<i32> = &mut v;
my_ref_mut(r1);
let r2 = r1;
my_ref_mut(r1);
}
{
let r: &Vec<i32> = &v;
my_ref(r);
my_ref(r);
}
{
let r1: &Vec<i32> = &v;
my_ref(r1);
let r2: &Vec<i32> = r1;
my_ref(r1);
}
}
The error is self explanatory:
error[E0382]: use of moved value: `*r1`
--> src/main.rs:20:20
|
19 | let r2 = r1;
| -- value moved here
20 | my_ref_mut(r1);
| ^^ value used here after move
|
= note: move occurs because `r1` has type `&mut std::vec::Vec<i32>`, which does not implement the `Copy` trait
I would have expected it to be use of moved value: r1
, not *r1
, because I have moved the reference, not the value itself.
By changing line 19 to let r2: &mut Vec<i32> = r1;
, thus specifying the type of r2
explicitly, the error becomes E0499:
error[E0499]: cannot borrow `*r1` as mutable more than once at a time
--> src/main.rs:20:20
|
19 | let r2: &mut Vec<i32> = r1;
| -- first mutable borrow occurs here
20 | my_ref_mut(r1);
| ^^ second mutable borrow occurs here
21 | }
| - first borrow ends here
This error also seems wrong to me, because the first borrow of *r1
should be the one on line 17 (let r1: &mut Vec<i32> = &mut v;
). I know about autoref and Deref coercion, but from what I believe, they are not applicable here.
My conclusion is that &T
is Copy
, as expected and as the second example above demonstrates. But I cannot say the same thing about &mut T
. I would like someone to explain to me the compilation errors and why &mut T
sometimes seems to behave like being Copy
. Is it also possible for this to be a compiler bug? My toolchain is:
stable-x86_64-unknown-linux-gnu (default)
rustc 1.25.0 (84203cac6 2018-03-25)