Move with type annotation

I'm new to Rust. I understand that the below code doesn't compile because of the use of moved value.

    let mut x: i32 = 1;
    let rx = &mut x;
    let arx = rx;
    *rx = 2; // error: use of moved value: `rx`

But if I annotate variable arx with type information, the code compiles fine.

    let mut x: i32 = 1;
    let rx = &mut x;
    let arx: &mut i32 = rx;
    *rx = 2;

Why does the code compile when annotated with type information?

rustc 1.60.0 (7737e0b5c 2022-04-04)

I think the difference is between moving and reborrowing, the latter of which is honestly not well documented although the semantics work intuitively in many/most cases, but I'm not sure why the addition of a type annotation is what makes the difference. Probably it's about the fact that every time you write & (mut) T it actually means &'a (mut) T for some compiler-assigned lifetime a.

1 Like

I believe its related to type inference. The same way, a mutable reference passed to a function expecting &mut … reborrows, while passed to a generic function that takes any type, it drops it.


fn consume_mut_ref<T>(_: &mut T) {}
fn consume_val<T>(_: T) {}

fn main() {
    let x = &mut 0;
    
    consume_mut_ref(x); // reborrows
    consume_mut_ref(x); // reborrows
    consume_val::<&mut _>(x); // reborrows
    consume_val::<&mut _>(x); // reborrows
    consume_val(x); // moves
    consume_val(x); // fails
}

The logic might be something like: reborrow when you know you have a (mutable) reference type, otherwise move. Only after a move is decided, this move is used in type inference to figure out the connection between the types, and infer the types. Once it knows there's a mutable reference, its too late to switch to re-borrowing. Or something like that... just a guess though :slight_smile:

1 Like