gpt4 book ai didi

rust - 回调到可变的 self

转载 作者:行者123 更新时间:2023-11-29 08:10:53 25 4
gpt4 key购买 nike

有没有一种方法(使用rust )可以在没有我在以下 MWE 中使用的 mem::replace hack 的情况下将可变借来的 self 发送到回调?我正在使用 Rust Stable (1.11.0)。

use std::mem;

trait Actable {
fn act(&mut self);
}

// Not Cloneable
struct SelfCaller {
message: String,
callback: Box<FnMut(&mut SelfCaller)>,
// other stuff
}

impl Actable for SelfCaller {
fn act(&mut self) {
fn noop(_: &mut SelfCaller) {}
let mut callback = mem::replace(&mut self.callback, Box::new(noop));
callback(self);
mem::replace(&mut self.callback, callback);
}
}

impl Drop for SelfCaller {
fn drop(&mut self) {/* unimiportant to the story */}
}

fn main() {
fn change(messenger: &mut SelfCaller) {
messenger.message = "replaced message".to_owned();
}

let mut messenger = SelfCaller {
message: "initial message".to_owned(),
callback: Box::new(change),
};

messenger.act();

println!("{}", &messenger.message);
}

Play

最佳答案

不,没有办法,因为这样做不安全。这是一个演示原因的示例(需要夜间编译器)。

#![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

好的,那怎么回事?首先,我为 SelfCaller 编写了 act 的实现,这样我可以在没有 mem::的情况下调用回调:替换,使用mem::transmute 让编译器生成一个与self 断开连接的新生命周期。

然后,我编写了一个回调(使用结构 Callback,因为我需要一个同时实现 FnMutDrop 的类型来演示通过更改其 callback 成员来改变 SelfCaller 的问题)。这具有删除先前回调的效果,这是当前正在执行的回调!如果 Callback 包含数据成员,尝试读取它们会导致未定义的行为,因为它们现在位于已释放的内存中(我们丢弃了整个 Box)。


顺便说一句,在您使用 mem::replace 的代码中,回调无法更改回调,因为您在回调调用结束后恢复了回调。

关于rust - 回调到可变的 self ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39137364/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com