所有提供的示例都可以在
rust Playground 中运行,轻松注释和取消注释相关函数以进行测试。 此外,为了清楚起见,所有示例都使用以下类型别名:
pub type MyOp<T> = dyn Fn(&mut String, &mut T);
下面的示例显示了有问题的代码:
fn test<T>() -> Vec<Box<MyOp<T>>> {
let mut operators: Vec<Box<MyOp<T>>> = Vec::default();
let mut add_op = |operator: Box<MyOp<T>>| {
let operator_bis = move |s: &mut _, t: &mut _| {
operator(s, t);
// Do something else with s
};
operators.push(Box::new(operator_bis));
};
add_op(Box::new(|s, t| ()));
add_op(Box::new(|s, t| ()));
operators
}
此代码无法编译,并出现以下错误,这是我没想到的,因为 T
的生命周期不应影响最终盒装闭包的生命周期。
error[E0310]: the parameter type `T` may not live long enough
--> src/main.rs:14:24
|
14 | operators.push(Box::new(operator_bis));
| ^^^^^^^^^^^^^^^^^^^^^^
| |
| the parameter type `T` must be valid for the static lifetime...
| ...so that the type `T` will meet its required lifetime bounds
|
help: consider adding an explicit lifetime bound
|
6 | fn test<T: 'static>() -> Vec<Box<MyOp<T>>> {
| +++++++++
有趣的是,不调用运算符闭包就可以编译,但显然代码并没有达到我最初的目标。
fn test<T>() -> Vec<Box<MyOp<T>>> {
let mut operators: Vec<Box<MyOp<T>>> = Vec::default();
let mut add_op = |operator: Box<MyOp<T>>| {
operators.push(operator);
};
add_op(Box::new(|_s, _rng| ()));
add_op(Box::new(|_s, _rng| ()));
operators
}
下面的示例显示了依赖辅助函数来修改闭包的工作版本。
该版本的优点是可以接受盒装和非盒装封口。
fn add_operator<T>(
operator: impl Fn(&mut String, &mut T) + 'static,
operators: &mut Vec<Box<MyOp<T>>>,
) {
let op = move |s: &mut _, t: &mut _| {
operator(s, t);
// Do something else with s
};
operators.push(Box::new(op));
}
fn test<T>() -> Vec<Box<MyOp<T>>> {
let mut operators = Vec::default();
add_operator(Box::new(|s: &mut _, t: &mut _| ()), &mut operators);
add_operator(|s, t| (), &mut operators);
operators
}
但是,我也希望下面的版本只接受闭包进行编译:
fn add_operator<T>(
operator: Box<MyOp<T>>,
operators: &mut Vec<Box<MyOp<T>>>,
) {
let op = move |s: &mut _ , t: &mut _| {
operator(s, t);
// Do something else with s
};
operators.push(Box::new(op));
}
fn test<T>() -> Vec<Box<MyOp<T>>> {
let mut operators = Vec::default();
add_operator(Box::new(|s: &mut _, t: &mut _| ()), &mut operators);
add_operator(Box::new(|s: &mut _, t: &mut _| ()), &mut operators);
operators
}
我认为这可能与 Rust 存储库上的 this issues 有关,因为编译器无法检测到 T
的生命周期并不真正相关。 但是,我对与闭包相关的生命周期问题的理解并没有那么有信心,在提出问题之前,我想知道是否有人可以查明我的代码中的错误,或者是否所有版本都应该能够编译。
pub type MyOp<T> = dyn Fn(&mut String, &mut T);
相当于
pub type MyOp<T> = dyn Fn(&mut String, &mut T) + 'static;
。您需要为类型别名添加生命周期,并且还需要使用它的函数。如果你正确地用生命周期注释你的代码,它就会编译:
pub type MyOp<'a, T> = dyn Fn(&mut String, &mut T) + 'a;
fn add_operator<'a, T: 'a>(
operator: Box<MyOp<'a, T>>,
operators: &mut Vec<Box<MyOp<'a, T>>>,
) {
let op = move |s: &mut _ , t: &mut _| {
operator(s, t);
// Do something else with s
};
operators.push(Box::new(op));
}
fn test<'a, T: 'a>() -> Vec<Box<MyOp<'a, T>>> {
let mut operators = Vec::default();
add_operator(Box::new(|s: &mut _, t: &mut _| ()), &mut operators);
add_operator(Box::new(|s: &mut _, t: &mut _| ()), &mut operators);
operators
}