Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cannot borrow captured outer variable in an Fn closure when using a closure with an Rc

Tags:

rust

use std::rc::Rc;

fn f1(cb: Box<Fn(i32) -> i32>) {
    let res = cb(15);
    println!("res {}", res);
}

fn main() {
    let mut v2 = Rc::new(5_i32);

    // 1
    // f1(Box::new(move |x: i32| *v2 + x));

    // 2
    f1(Box::new(move |x: i32| {
        let tmp = *v2;
        *Rc::get_mut(&mut v2).unwrap() = tmp + 1;
        x + *v2
    }));
}

The code referenced as "1", if uncommented, compiles and runs just fine, but the code referenced as "2" does not compile, failing with the message:

error[E0596]: cannot borrow `v2` as mutable, as it is a captured variable in a `Fn` closure

How can I fix this, if I want keep the code structure as it is?

In my real code, I want connect two traits. One of them will call a callback on event, and the other has a function to handle the callback:

trait Foo {
    fn add_callback(&mut self, cb: Box<Fn(i32)>);
}

trait Boo {
    fn on_new_data(&mut self, data: i32);
}

I want to create a trait object with Boo, wrap it with Rc, and pass it to Foo::add_callback in the form of |x:i32| Rc::get_mut(&mut boo).unwrap().on_new_data(x)

like image 403
user1244932 Avatar asked Oct 19 '22 03:10

user1244932


1 Answers

The entire error message is mostly helpful:

error[E0596]: cannot borrow `v2` as mutable, as it is a captured variable in a `Fn` closure
  --> src/main.rs:17:19
   |
17 |      *Rc::get_mut(&mut v2).unwrap() = tmp + 1;
   |                   ^^^^^^^ cannot borrow as mutable
   |
help: consider changing this to accept closures that implement `FnMut`
  --> src/main.rs:15:17
   |
15 |       f1(Box::new(move |x: i32| {
   |  _________________^
16 | |      let tmp = *v2;
17 | |      *Rc::get_mut(&mut v2).unwrap() = tmp + 1;
18 | |      x + *v2
19 | |     }));
   | |_____^

Changing f1 to accept a FnMut and making the variable mutable allows the code to compile:

fn f1(mut cb: Box<FnMut(i32) -> i32>) {

This is needed in order to mutate the captured variable v2, required by the &mut v2 argument to Rc::get_mut.

like image 73
Shepmaster Avatar answered Oct 21 '22 05:10

Shepmaster