Is it possible for a mutable reference to be moved?

https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=df89b680ad8e18bf418f1f630433794d

This fails to compile because "r is moved", which goes against my intuition, since &mut T is Copy iirc.

What am I missing?

&mut T isn't Copy, because that would result in multiple exclusive references to the same T. You can reborrow it, though. This fixes the problem:

fn act<T: Read + Seek>(r: &mut T)
{
    {
        let mut a = Reader::new(&mut *r);
        a.read().unwrap();
    }
    
    {
        let mut b = Reader::new(r);
        b.read();
    }
}
1 Like

Mutable references are not Copy. If they were, you could trivially construct multiple mutable references to the same backing object.

1 Like

Oh, I see.
So why does this compile?

https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=90b389fbe7d08ad7921295121cca1e67

The type is changed, but the use of r is the same

The two lifetimes don't overlap, that is why. If you actually try to use a after constructing b, it fails to compile, as expected.

The reason is a bit technical and IMO arbitrary. Basically whenever rust’s type checker can easily and early on figure out that a function takes a mutable reference as an argument, then it will implicitly introduce a re-borrow instead of moving the mutable reference. Similar behavior can be seen when you assign variables. E.g.

let mut x = 42;
let y = &mut x;
let z = y;
dbg!(y);

won’t work, but

let mut x = 42;
let y = &mut x;
let z: &mut i32 = y;
dbg!(y);

or

let mut x = 42;
let y = &mut x;
let z: &mut _ = y;
dbg!(y);

will, because the type checker sees early on that the variable z is a mutable reference, so the assigned value y will be re-borrowed, basically turning the code into the equivalent

let mut x = 42;
let y = &mut x;
let z: &mut _ = &mut *y;
dbg!(y);

In your code example the difference is between a function generically expecting any type T or any mutable reference type &mut T, in the latter case the compiler will introduce the re-borrow for you. It’s a bit stupid/arbitrary of course, since the compiler does eventually figure out that it’s dealing with mutable references in both cases.


I personally think that we should try to change rustc in the future so that all of the above compiles. Such a change should also make your original code compile.

5 Likes