Passing &mut T to a function

This program doesn't compile due to the fact that &mut i32 doesn't implement Copy trait.

let value = &mut 10;
let reader = value; // moved
println!("{}", value); // error as expected

But, I don't quite understand why this compiles:

fn function(value: &mut i32) { ... }

fn main() {
  let value = &mut 10;
  function(value); // <- Should be moved?...
  println!("{}", value);
}

If &mut i32 doesn't implement Copy then value should be moved to the function...

There is an implicit reborrow happening when you call function, which allows you to continue using the exclusive reference afterwards.

fn function(value: &mut i32) { ... }

fn main() {
  let value = &mut 10;
  function(value); // <- reborrow here
  println!("{}", value);
}
2 Likes

Do I correctly understand that if I will define the type of a variable in the first example then reborrowing also will be applied?

let value = &mut 32;
let reader: &mut i32 = value; // reborrow?
println!("{}", value);

If this is our baseline:

fn function(reborrowed_value: &mut i32) {
    
} // reborrowed_value goes out of scope here

fn main() {
    let value = &mut 10;
    function(value);
    println!("{}", value);
}

I believe the function-less equivalent version would be:

fn main() {
    let value = &mut 10;
    {
        let reborrowed_value = &mut *value; // re-borrow, not move
    } // reborrowed_value goes out of scope here
    println!("{}", value);
}
1 Like

This is much clearer. Thanks.

Seems like re-borrowing applies in any case except:

let value = &mut 10;
let reader = value;

Reborrow will only happen if there is no type inference. For example, reborrow doesn't happen in any of these cases

fn function<T>(value: T) {}

fn main() {
    let x = &mut 0;
    function(x);
    let y = x;
}
fn function<T>(value: T) {}

fn main() {
    let x = &mut 0;
    let z = x;
    let y = x;
}

But it will in these

fn function<T>(value: T) {}

fn main() {
    let x = &mut 0;
    function::<&mut i32>(x);
    let y = x;
}
fn function<T>(value: T) {}

fn main() {
    let x = &mut 0;
    let z: &mut i32 = x;
    let y = x;
}
5 Likes

Thank you very much!

Can you please explain why this is? Or link me to somewhere that explains why reborrows work this way?

It's not clear to me why a re-borrow only happens when no type inference is involved.

It's to reduce confusion. If there is any type inference, then we don't do reborrows or coercions. This keeps things simpler, and easier to follow in the face of type inference.

3 Likes

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.