不,没有办法,因为这样做不安全。这是一个演示原因的示例(需要夜间编译器)。
#![feature(fn_traits)]
#![feature(unboxed_closures)]
use std::mem;
trait Actable {
fn act(&mut self);
}
struct SelfCaller {
message: String,
callback: Box<FnMut(&mut SelfCaller)>,
}
impl Actable for SelfCaller {
fn act(&mut self) {
let mut callback: &mut Box<FnMut(&mut SelfCaller)> = unsafe { mem::transmute(&mut self.callback) };
println!("calling callback");
callback(self);
println!("called callback");
}
}
struct Callback;
impl Drop for Callback {
fn drop(&mut self) {
println!("Callback dropped!");
}
}
impl<'a> FnOnce<(&'a mut SelfCaller,)> for Callback {
type Output = ();
extern "rust-call" fn call_once(mut self, args: (&mut SelfCaller,)) {
self.call_mut(args)
}
}
impl<'a> FnMut<(&'a mut SelfCaller,)> for Callback {
extern "rust-call" fn call_mut(&mut self, (messenger,): (&mut SelfCaller,)) {
println!("changing callback");
messenger.callback = Box::new(|messenger| {});
println!("changed callback");
messenger.message = "replaced message".to_owned();
}
}
fn main() {
let change = Callback;
let mut messenger = SelfCaller {
message: "initial message".to_owned(),
callback: Box::new(change),
};
messenger.act();
println!("{}", &messenger.message);
}
该程序的输出是:
calling callback
changing callback
Callback dropped!
changed callback
called callback
replaced message
好吧,那到底是怎么回事?首先,我写了实现act
for SelfCaller
以这样的方式我can调用回调而不mem::replace
, using mem::transmute
让编译器生成一个新的生命周期,与self
.
然后,我编写了一个回调(使用结构Callback
,因为我需要一个同时实现两者的类型FnMut
and Drop
来证明问题),这会改变SelfCaller
通过改变其callback
成员。这有以下效果删除之前的回调,这是当前正在执行的回调!如果Callback
包含数据成员,尝试读取它们会导致未定义的行为,因为它们现在位于已释放的内存中(我们删除了整个Box
).
顺便说一下,在你的代码中使用mem::replace
,回调不能更改回调,因为您在回调调用结束后恢复回调。