Some questions about `E0521`

fn main() {
    let mut a: &mut i32 = &mut 1;

    let mut closure = || {
        a = &mut 2; //Error
    };

    closure();
}

Error:

error[E0521]: borrowed data escapes outside of closure
 --> src\main.rs:5:9
  |
2 |     let mut a : &mut i32 = &mut 1;
  |         ----- `a` declared here, outside of the closure body
...
5 |         a = &mut 2; // Error
  |         ^^^^------
  |         |   |
  |         |   borrow is only valid in the closure body
  |         reference escapes the closure body here

For more information about this error, try `rustc --explain E0521`.

I don't understand why reference escapes the closure ?

Because you assign it to the variable defined outside the closure.

1 Like

But isn’t it capturing the variable a?

By default, the closure uses the weakest way to capture all its variables. Assignment to a requires only a &mut a, so that's what is captured. Thus you try to write a local &mut 2 into a nonlocal variable and get an error. You can force the closure to capture a by move using the move keyword:

let mut closure = move || { a = &mut 2; }

However, it also won't work, since a itself is a nonlocal reference &mut 1. You should declare

let mut a = 1;

and capture a by move.

In order for the variable a of type &mut i32 to have a valid value, that value must be a pointer to some memory that can be mutated. That memory must be valid for as long as a is being used. The code in the closure, a = &mut 2, doesn't work because it's pointing to a temporary place that is deallocated at the end of its statement.

The reason that the original declaration let mut a: &mut i32 = &mut 1; is valid is because of a special convenience rule called β€œtemporary lifetime extension”, which says that inside of a let temporaries may be adjusted to live as long as a variable does. Specifically,

let mut a: &mut i32 = &mut 1;

acts as if it was

let mut tmp: i32 = 1;
let mut a: &mut i32 = &mut tmp;

However, maybe your goal is to change the value stored in the &mut i32? In that case, the correct code is:

    let mut closure = || {
        *a = 2;
    };

That is, we are assigning to the referent of the mutable reference a, not replacing the mutable reference itself.

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.