fn g(a: &mut i32) {
let b = a;
*b = 11;
println!("{}", b);
}
fn main() {
let a: &mut i32 = &mut 10;
{
let b = a;
println!("{}", b);
}
println!("{}", a);
}
fn main() {
let a: &mut i32 = &mut 10;
g(a);
println!("{}", a);
}
The first main compile failed with the error borrow of moved value:a``, but the second main compile successfully. I thought that calling g also move the value a. What happens here?
Imagine the variable a has a type &'a mut i32 for some lifetime 'a. What you have in the second example is a "reborrow": the reference inside the function is &'b mut i32 with a shorter lifetime 'b that ends before the final println.
You can also change the first example to work by explicitly adding a type annotation, which allows a different lifetime:
Put simply, in certain cases when the compiler sees that a &mut T would be moved (without needing to do too much type inference first), a re-borrow is introduced instead, with the effect that g(a) becomes essentially re-written into g(&mut *a) here by the compiler. (The rule exists for convenience so you don't have to write g(&mut *a) yourself.) So a is not moved after all, instead a new reference is created pointing to the same target (and a becomes unusable for as long as that new reference lives).
Re-borrows are a “generalization” of moves in the sense that re-borrowing a &'a mut Tcan also produce a &'a mut T with the same lifetime which has (almost) the same effects as a move. But, as @tczajka mentioned, it can also produce a shorter-lived reference. Naturally, only in the latter case of producing a shorter-lived new reference, the original reference will ever become usable again.
The fact that re-borrowing “generalizes” moving in this sense is essential because it means that you never need to truly move a reference in such a function call like in your example. Otherwise this “automatic rewriting” would be highly inconvenient, because it prevents you from “actually” moving a &mut T into a function call (in a straightforward manner).