rustclosuresbox

What is the different of Box<closure> and closure?


let mut x = 10;
let mut closure: Box<dyn FnMut() -> i32> = Box::new(|| {
    println!("x = {}", x);
    x += 5;
    x
});

let value1 = closure(); // x = 10
let value2 = closure(); // x = 15
let value3 = closure(); // x = 20
println!(
    "value1 = {}, value2 = {}, value3 = {}",
    value1, value2, value3
);
// println!("After closure call, x = {}", x); // error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable
let mut x = 10;
let mut closure = || {
    println!("x = {}", x);
    x += 5;
    x
};

let value1 = closure(); // x = 10
let value2 = closure(); // x = 15
let value3 = closure(); // x = 20
println!(
    "value1 = {}, value2 = {}, value3 = {}",
    value1, value2, value3
);
println!("After closure call, x = {}", x); // x is ok for printing.

My questions:

  1. what type of closure in 2nd code?

  2. Why closure wrapped by Box pointer in first code is different with closure alone in second one?

  3. How can i use x after closure? the right way is?


Solution

    1. what type of closure in 2nd code?

      As documented in the Rust Reference chapter on Closure Types:

      A closure expression produces a closure value with a unique, anonymous type that cannot be written out.

    2. Why closure wrapped by Box pointer in first code is different with closure alone in second one?

      Both closures exclusively borrow x. So long as they're "alive", x cannot be accessed from elsewhere.

      Prior to Rust v1.63, both closures remained alive until the end of the lexical scope—causing their borrows of x also to continue beyond your println! statements. However, thanks to non-lexical lifetimes, Rust is now able to determine that closure ceases to be alive (and its borrows end) after its last use.

      In the non-Box case, closure is last used in the assignment to value3.

      In the Box case, closure is last used when it is destroyed (implicitly at the end of the lexical scope): Box has a Drop handler (that frees its heap allocation) that could theoretically make use of the exclusive borrow of x. Therefore, in that case, closure's borrows must continue until then.

    3. How can i use x after closure? the right way is?

      Once you've finished using closure, you could explicitly drop(closure);. Its exclusive borrow of x would then end, permitting you to use x again thereafter.