在Rust中,我试图创建一个回调函数列表以便稍后调用:
use std::vec::Vec;
fn add_to_vec<T: FnMut() -> ()>(v: &Vec<Box<FnMut() -> ()>>, f: T) {
v.push(Box::new(f));
}
fn call_b() {
println!("Call b.");
}
#[test]
fn it_works() {
let calls: Vec<Box<FnMut() -> ()>> = Vec::new();
add_to_vec(&calls, || { println!("Call a."); });
add_to_vec(&calls, call_b);
for c in calls.drain() {
c();
}
}
我主要遵循建议here on how to store a closure,但是,我仍然看到一些错误:
src/lib.rs:6:12: 6:23 error: the parameter type `T` may not live long enough [E0311]
src/lib.rs:6 v.push(Box::new(f));
^~~~~~~~~~~
src/lib.rs:6:23: 6:23 help: consider adding an explicit lifetime bound for `T`
src/lib.rs:5:68: 7:2 note: the parameter type `T` must be valid for the anonymous lifetime #1 defined on the block at 5:67...
src/lib.rs:5 fn add_to_vec<T: FnMut() -> ()>(v: &Vec<Box<FnMut() -> ()>>, f: T) {
src/lib.rs:6 v.push(Box::new(f));
src/lib.rs:7 }
src/lib.rs:6:12: 6:23 note: ...so that the type `T` will meet its required lifetime bounds
src/lib.rs:6 v.push(Box::new(f));
^~~~~~~~~~~
我已尝试将功能签名更改为:
fn add_to_vec<'a, T: FnMut() -> ()>(v: &Vec<Box<FnMut() -> ()>>, f: &'a T) {
...但这让我:
src/lib.rs:6:12: 6:23 error: the trait `core::ops::Fn<()>` is not implemented for the type `&T` [E0277]
src/lib.rs:6 v.push(Box::new(f));
^~~~~~~~~~~
error: aborting due to previous error
src/lib.rs:6:12: 6:23 error: the trait `core::ops::Fn<()>` is not implemented for the type `&T` [E0277]
src/lib.rs:6 v.push(Box::new(f));
^~~~~~~~~~~
src/lib.rs:18:24: 18:51 error: mismatched types:
expected `&_`,
found `[closure src/lib.rs:18:24: 18:51]`
(expected &-ptr,
found closure) [E0308]
src/lib.rs:18 add_to_vec(&calls, || { println!("Call a."); });
^~~~~~~~~~~~~~~~~~~~~~~~~~~
(我可以通过添加&
来纠正的最后一个错误;虽然我认为这是我应该需要的,因为add_to_vec
最终将拥有闭包,因此需要借用它,我不完全确定。)
答案 0 :(得分:3)
您的代码存在一些问题。这是一个完全固定的版本:
use std::vec::Vec;
fn add_to_vec<'a, T: FnMut() + 'a>(v: &mut Vec<Box<FnMut() + 'a>>, f: T) {
v.push(Box::new(f));
}
fn call_b() {
println!("Call b.");
}
#[test]
fn it_works() {
let mut calls: Vec<Box<FnMut()>> = Vec::new();
add_to_vec(&mut calls, || { println!("Call a."); });
add_to_vec(&mut calls, call_b);
for mut c in calls.drain() {
c();
}
}
生命周期问题是盒装函数对象必须具有共同的基本生命周期;如果您只是编写通用约束T: FnMut()
,则假定只需要函数调用就可以生存,而不再需要。因此,需要向它添加两件事:泛型参数T
必须约束到指定的生命周期,并且为了将其存储在向量中,特征对象类型必须同样受到约束,如{{1 }}。这样它们就可以匹配并确保内存安全,因此编译器可以通过它。顺便说一下,Box<FnMut() + 'a>
的{{1}}部分是多余的。
需要进行的其余修复是插入一些-> ()
;为了推送向量,你自然需要一个可变引用,因此FnMut() -> ()
到mut
会发生变化,并且为了对&
和&mut
进行可变引用绑定必须calls
。