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
}));
}
Run Code Online (Sandbox Code Playgroud)
如果未注释,引用为“1”的代码可以正常编译并运行,但引用为“2”的代码无法编译,失败并显示消息:
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
}));
}
Run Code Online (Sandbox Code Playgroud)
如果我想保持代码结构不变,我该如何解决这个问题?
在我的真实代码中,我想连接两个特征。其中一个将调用事件回调,另一个有一个函数来处理回调:
trait Foo {
fn add_callback(&mut self, cb: Box<Fn(i32)>);
}
trait Boo {
fn on_new_data(&mut self, data: i32);
}
Run Code Online (Sandbox Code Playgroud)
我想用 创建一个特征对象Boo,用 包装它Rc,然后Foo::add_callback以|x:i32| Rc::get_mut(&mut boo).unwrap().on_new_data(x)
整个错误消息大多有帮助:
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 | | }));
| |_____^
Run Code Online (Sandbox Code Playgroud)
更改f1为接受 aFnMut并使变量可变允许代码编译:
fn f1(mut cb: Box<FnMut(i32) -> i32>) {
Run Code Online (Sandbox Code Playgroud)
这是为了改变捕获的变量所必需的,这是参数 tov2所需要的。&mut v2Rc::get_mut