Borrowing vector of boxed functions


Hi, I tried putting together code that looks something like this:

fn f1(x: i32) -> i32 {
    x + 1

fn f2(x: i32) -> i32 {
    x + 2

fn do_test(v: &mut Vec<Box<Fn(i32)-> i32>>) {

pub fn main() {
    let mut func_list: Vec<Box<Fn(i32)-> i32>> = Vec::new();
        let borrow = &mut func_list;
    for func in func_list.iter_mut() {
        println!("{}", func(3));

Which results in the following error:

<anon>:20:17: 20:26 error: cannot borrow `func_list` as mutable more than once at a time
<anon>:20     for func in func_list.iter_mut() {
<anon>:17:27: 17:36 note: previous borrow of `func_list` occurs here; the mutable borrow prevents subsequent moves, borrows, or modification of `func_list` until the borrow ends
<anon>:17         let borrow = &mut func_list;
<anon>:23:2: 23:2 note: previous borrow ends here
<anon>:14 pub fn main() {
<anon>:23 }

Why does the borrow last until the end of main and not live only for the block in which borrow is declared?


This works

I added an explicit lifetime bound on the object. The problem was that the borrow could’ve escaped into a boxed closure in the vector within the call to do_test. By specifying the lifetimes such that this is impossible, the borrow can end before the vector goes out of scope.

I’m not entirely sure why eliding the lifetimes led to the same lifetime being used for the object as for the Vec reference. Usually, the lifetimes would automatically be distinct, but I’ll have to look into the rules specific to objects to see if this is working as intended.

Edit: Okay, yes, this is the intended behaviour:

The default object lifetime rule explicitly overrides the normal fresh lifetime rule, so that the lifetimes are the same. To circumvent that, you need to specify a fresh lifetime. Without that, the borrow can escape into the object, so the borrow is indefinite.

Edit 2: Here’s an example of the kind of code the error you got prevents:
As you can see, if this code compiled, I’d end up with two mutable references to the second element of the vector at the end of main (one of which is held in the first element), which is a huge no-no in Rust.