提问人:Makogan 提问时间:8/24/2022 更新时间:8/24/2022 访问量:56
包含数据的通用回调
generic callback with data
问:
关于这个话题已经有一个非常流行的问题,但我不;T完全理解答案。
目标是:
我需要一个“函数指针”列表(读取 Vec),用于修改存储在程序中其他地方的数据。我能想到的最简单的例子是按下某个键时调用的回调。因此,当按下任何键时,传递给对象的所有函数都将按某种顺序调用。
读到答案,我不清楚我怎么能列出这样的清单。听起来我需要将回调的类型限制为已知的类型,否则我不知道您将如何创建它的数组。
我也不清楚如何存储数据指针/引用。
说我有
struct Processor<CB>
where
CB: FnMut(),
{
callback: CB,
}
就像答案所暗示的那样,我不能制作处理器阵列,不是吗?因为每个处理器在技术上都是不同的类型,具体取决于通用版本。
答:
5赞
jthulhu
8/24/2022
#1
事实上,你不能做一个处理器的向量。通常,闭包都有不同的、不可命名的类型。相反,您需要的是 trait 对象,它允许您动态调度回调调用。由于这些不是 ,您可能希望将它们放在 .最后一种类型是 。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()
}
}
参观游乐场
但是,如果您这样做,您可能会在生命周期方面遇到一些问题(因为您要么强制移入所有内容,要么只修改生命周期的值,这不是很方便。相反,以下方法可能会更好'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);
}
参观游乐场
需要注意的几点:
- 您必须手动向生产者提交,否则 Rust 会抱怨它会在范围的末尾被删除,但它包含(通过闭包)对 的独占引用,这是不行的,因为我尝试阅读它。
drop
modified
- 当前,取一个 ,因为我们只需要一个 .如果你希望它只是一个 ,你需要替换为 ,这意味着回调仍然可以修改它们外部的内容,但不能修改内部的内容。
run_callbacks
&mut self
FnMut
&self
FnMut
Fn
评论
0赞
Makogan
8/24/2022
为了完整起见,您将如何称呼这些对象为循环?
0赞
jthulhu
8/24/2022
@Makogan我也添加了一个示例。
2赞
Bamontan
8/24/2022
#2
是的,所有的闭包都是不同的类型,所以如果你想拥有不同闭包的 vec,你需要使它们成为特征对象。这可以是 archieve(或任何智能指针)。 实现,因此您可以拥有并可以对它们进行 vec,并调用它们的回调: playgroundBox<dyn Trait>
Box<dyn FnMut()>
FnMut()
Processor<Box<dyn FnMut()>>
评论