我试图在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));
}
有没有办法解决这个问题,还是我遇到了编译器错误?
使用rustc 1.15.0(10893a9a3 2017-01-19)。
另见Rust 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
}
}
但我找不到克隆盒装函数的方法......
答案 0 :(得分:2)
你在这里有借款问题:
self.func
不可变的self
这是不允许的,因为它可以让你在使用时更改func
,这预示着麻烦。
您可以尝试将Callback
更改为仅传入&mut i32
,但之后您会遇到终身统一问题:
exec
需要&'a mut self
,那么您锚定该对象,在其余生中借用它,'a
,并且您需要'a
签名Callback
。两种情况都不奏效。
因此,解决方案是首先避免使用寿命。
它也更容易(在借用时)不传递self
的实例,而只是传递对self.val
的引用,所以我首先提出:
type Callback = Fn(&mut i32, i32) -> i32;
struct Func {
val: i32,
func: Option<Box<Callback>>,
}
impl Func {
fn exec(&mut self, val: i32) -> i32 {
if let Some(ref f) = self.func {
return f(&mut self.val, val);
};
0i32
}
}
fn main() {
let mut a32 = Func{
val: 10i32,
func: Some(Box::new(|s: &mut i32, val: i32| -> i32 {
let v = *s;
*s += 1;
val * 32 + v
}))
};
println!("a32(4) = {}", a32.exec(4i32));
println!("a32(4) = {}", a32.exec(4i32));
}
如果你想真正通过Func
,你需要选择跳舞&#34;:
impl Func {
fn exec(&mut self, val: i32) -> i32 {
let func = self.func.take();
let res = if let Some(ref f) = func {
f(self, val)
} else {
0i32
};
self.func = func;
res
}
}
请注意,self.func
在回调中为空。