Mak*_*gan 1 events callback rust
关于这个主题已经有一个非常受欢迎的问题,但我不完全理解答案。
目标是:
我需要一个“函数指针”列表(读取 Vec)来修改存储在程序中其他位置的数据。我能想到的最简单的例子是按下按键时调用的回调。因此,当按下任意键时,传递给该对象的所有函数都将按某种顺序调用。
阅读答案后,我不清楚如何才能列出这样的列表。听起来我需要将回调的类型限制为已知的类型,否则我不知道如何创建它的数组。
我也不清楚如何存储数据指针/引用。
说我有
struct Processor<CB>
where
CB: FnMut(),
{
callback: CB,
}
Run Code Online (Sandbox Code Playgroud)
就像答案所暗示的那样,我无法制作处理器阵列,可以吗?因为每个处理器在技术上都是不同的类型,具体取决于通用实例。
事实上,你无法制作处理器向量。通常,闭包都有不同的、不可命名的类型。相反,您想要的是特征对象,它允许您动态调度回调调用。由于这些不是Sized,您可能希望将它们放入Box. 最终的类型是Vec<Box<dyn FnMut()>>.
fn add_callback(list: &mut Vec<Box<dyn FnMut()>>, cb: impl FnMut() + 'static) {
list.push(Box::new(cb))
}
fn run_callback(list: &mut [Box<dyn FnMut()>]) {
for cb in list {
cb()
}
}
Run Code Online (Sandbox Code Playgroud)
看操场
但是,如果您确实这样做,则生命周期可能会出现一些问题(因为您要么强制移入所有内容,要么只修改生命周期的值'static,这不是很方便。相反,以下可能会更好
#[derive(Default)]
struct Producer<'a> {
list: Vec<Box<dyn FnMut() + 'a>>,
}
impl<'a> Producer<'a> {
fn add_callback(&mut self, cb: impl FnMut() + 'a) {
self.list.push(Box::new(cb))
}
fn run_callbacks(&mut self) {
for cb in &mut self.list {
cb()
}
}
}
fn callback_1() {
println!("Hello!");
}
fn main() {
let mut modified = 0;
let mut prod = Producer::default();
prod.add_callback(callback_1);
prod.add_callback(
|| {
modified += 1;
println!("World!");
}
);
prod.run_callbacks();
drop(prod);
println!("{}", modified);
}
Run Code Online (Sandbox Code Playgroud)
看操场
只需注意以下几点:
drop生产者,否则 Rust 会抱怨它将在作用域末尾被删除,但它包含(通过闭包)对 的独占引用modified,这是不行的,因为我尝试读取它。run_callbacks取 a &mut self,因为我们只需要 a FnMut。如果您希望它只是 a &self,则需要替换FnMut为Fn,这意味着回调仍然可以修改它们外部的内容,但不能修改内部的内容。