Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When an immutable reference to a mutable reference to a value outside the scope is returned, why is the mutable reference dropped when the scope ends?

fn main() {
    // block1: fails
    {
        let mut m = 10;

        let n = {
            let b = &&mut m;
            &**b // just returning b fails
        };

        println!("{:?}", n);
    }

    // block2: passes
    {
        let mut m = 10;

        let n = {
            let b = &&m;
            &**b // just returning b fails here too
        };

        println!("{:?}", n);
    }
}

block1 fails with the error:

error[E0597]: borrowed value does not live long enough
  --> src/main.rs:7:22
   |
7  |             let b = &&mut m;
   |                      ^^^^^^ temporary value does not live long enough
8  |             &**b // just returning b fails
9  |         };
   |         - temporary value dropped here while still borrowed
...
12 |     }
   |     - temporary value needs to live until here

Am I correct in assuming that the inner immutable reference is extended beyond the block2 scope, whereas in block1, the inner mutable reference is always dropped even if there is an outer reference to it?

like image 580
soupybionics Avatar asked Jul 30 '18 09:07

soupybionics


People also ask

What is a mutable reference in Rust?

Back to Rust. A mutable reference is a borrow to any type mut T , allowing mutation of T through that reference. The below code illustrates the example of a mutable variable and then mutating its value through a mutable reference ref_i .

How do you borrow as mutable in Rust?

First, we change s to be mut . Then we create a mutable reference with &mut s where we call the change function, and update the function signature to accept a mutable reference with some_string: &mut String . This makes it very clear that the change function will mutate the value it borrows.

What is borrowing Rust?

What is Borrowing? When a function transfers its control over a variable/value to another function temporarily, for a while, it is called borrowing. This is achieved by passing a reference to the variable (& var_name) rather than passing the variable/value itself to the function.

What is a reference rust?

A reference represents a borrow of some owned value. You can get one by using the & or &mut operators on a value, or by using a ref or ref mut pattern.


1 Answers

It is sufficient here to think of a mutable borrow as a non-Copy struct (S in the snippets below) which takes ownership of the referenced value. This model represents the exclusive nature of a mutable borrow.

Reasoning based on this model: In block2 n is a reference to the original m, while in block1 n would end up being a reference to a copy of m owned by the mutable borrow. In both blocks the inner reference is dropped at the end of the let-block, but only in block1 this causes a problem, because in block1 the target of the reference for n is still owned by the inner reference when this inner reference is dropped.

struct S { m: i32 }
let mut m = 10;

let n = {
    let s = S { m };
    let b = &s;
    &(*b).m
}; // s is dropped

println!("{:?}", n);

In the snippet above s takes ownership of a copy of m. The reference n would point to that copy of n which is dropped when s is dropped - not allowed. If m was non-Copy, m would be moved into s, which would have the same implications.

In block2 the original m is borrowed directly without copying it. If you force a copy, you will get the same error as for block1:

let mut m = 10;

let n = {
    let m2 = m;
    let mut a = &m2;
    let b = &a;
    &**b
};

println!("{:?}", n);
like image 124
Calculator Avatar answered Oct 09 '22 18:10

Calculator