2

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)
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
asdragnea
  • 53
  • 1
  • 5

0 Answers0