我正在尝试在Rust中存储和使用可选的回调句柄,它类似于我正在存储的结构体的方法。只要我不将自身的引用传递给回调,它就可以工作。但是这样做会导致使用对象引用的生命周期错误(E0312)。生命周期似乎是一样的,我无法想出如何更改才能使其工作。
type Callback<'a> = Fn(&'a mut Func, i32) -> i32;
struct Func<'a> {
val: i32,
func: Option<Box<Callback<'a>>>,
}
impl<'a, 'b> Func<'b> {
fn exec(&'a mut self, val: i32) -> i32 {
if let Some(ref f) = self.func {
return f(self, val);
};
0i32
}
}
fn main() {
let mut a32 = Func{
val: 10i32,
func: Some(Box::new(|ref mut s, val: i32| -> i32 {
let v = s.val;
s.val += 1;
val * 32 + v
}))
};
println!("a32(4) = {}", a32.exec(4i32));
println!("a32(4) = {}", a32.exec(4i32));
}
有没有办法解决这个问题,还是我遇到了编译器的bug?
使用rustc 1.15.0(10893a9a3 2017-01-19)。
也可以在Rust playground上查看playground。
我也尝试了不使用显式生命周期,但是我遇到了一个问题,即我不能在Rust中创建引用别名(E0502)。
我知道Rust试图防止数据竞争,但这是否意味着在这些情况下我总是需要创建对象的副本?
以下内容也不起作用,会给我一个错误,即借用的内容无法移动出去(E0507)。
impl Func {
fn exec(&mut self, val: i32) -> i32 {
if self.func.is_some() {
return self.func.unwrap()(self, val);
};
0i32
}
}
但是我找不到克隆封装函数的方法...
&self
/&mut self
作为参数传递。但是请注意,今天你不能克隆任意闭包。它们不知道如何克隆自己。 - Matthieu M.self
,那么就可以避免这种“舞蹈”。否则的话,在回调函数中,您可能会在持有指向它的引用时覆盖self.func
字段。这将是...糟糕的。另一个解决方案是将结构体分成两个部分:回调函数在其字段中,其他所有内容在另一个私有的“子结构”中。这样,您就可以像使用i32
一样传递对子结构的可变引用。 - Matthieu M.exec
中使用对self
的_mutable_引用调用任何方法,因为这可能会使现有引用无效?因此,即使包装的函数对象是可克隆的,我仍然会陷入同样的问题... - user2525536f
被借用(在if
块期间),就不行,在之前和之后可以。 - Matthieu M.