我想要对列表中的更改进行回调,因此我创建了一个简单的示例:
struct Foo;
struct FooList {
list: Vec<Foo>,
on_change_cb: Vec<Box<FnMut(& mut [Foo])>>,
}
impl FooList {
/*
pub fn register_on_change_cb2<F>(&mut self, cb: F) where F: FnMut(&mut [Foo]) {
self.on_change_cb.push(Box::new(cb));
}*/
pub fn register_on_change_cb(&mut self, cb: Box<FnMut(&mut [Foo])>) {
self.on_change_cb.push(cb);
}
pub fn push(&mut self, foo: Foo) {
self.list.push(foo);
self.on_change();
}
fn on_change(&mut self) {
for cb in &mut self.on_change_cb {
cb(&mut self.list);
}
}
}
- 我没有给编译器任何关于生命周期的明确提示:
Vec<Box<FnMut(& mut [Foo])>>
,那么编译器在这里使用的生命周期是什么?如果我改变这样的代码:
struct FooList<'a> {
list: Vec<Foo>,
on_change_cb: Vec<Box<FnMut(&'a mut [Foo])>>,
}
impl<'a> FooList<'a> {
我得到一个编译时错误:
错误[E0495]:由于需求冲突,无法推断借用表达式的适当生命周期
-
如何以某种方式显式设置生命周期,使回调的
& mut [Foo]
的生命周期小于,但不等于整个FooList
对象的生命周期? -
我评论了
register_on_change_cb2
,我想允许在不使用Box::new
的情况下调用register_on_change_cb
但是失败了 . 如果取消注释register_on_change_cb2
,则会收到错误消息:
错误[E0310]:参数类型F的寿命可能不够长
如何在不需要 'static
生命周期的回调的情况下修复此错误?我只想打电话给 Box::new
.
1 回答
我将尝试回答你的问题1和3,因为问题2要么是多余的,要么与其他问题正交,我无法说出你真正想要实现的目标 . 也许它应该有自己的问题 .
这简称为higher ranked trait bound或HRTB . 它们主要用于
Fn
特征,这就是它们存在的原因 .on_change_cb
的类型是Vec<Box<FnMut(&mut [Foo])>>
,它不带任何生命周期信息,则它不能包含任何引用('static
引用除外) . 你需要说实现FnMut
的类型也可能包含(非'static
)引用,只要它们比生命周期更长'a
:这类似于:“对于每个
FooList
对象,有一个生命周期'a
,这样FooList
中的每个回调都只包含至少为'a
的引用 . ”这种解释可以更容易地为register_on_change_cb2
编写原型:它需要一个回调,它也只包含至少为'a
的引用 .(我想我现在
'a
的'a
正确 - 这个答案的先前版本错了 . )'a
lifetime让编译器保证你永远不会在Box
(因此Vec
)中放回一个回调,除非它至少和FooList
本身一样长 . 这很重要,因为闭包可以捕获对封闭范围中值的引用,如下面的代码(playground link)所示:在此示例中,您无法插入捕获
shortlived
的闭包,因为它不会超过(推断的)生命周期'a
. 但是你可以插入捕获longlived
的闭包,因为编译器可以推断满足两个约束的生命周期'a
:'a
必须比list
更长,因为list
的类型为FooList<'a>
.longlived
必须比'a
更长,因为借用longlived
的|_| println!("{}", longlived)
在register_on_change_cb2
的调用中受到'a
的限制 .如果你想说回调没有通过引用借用任何东西,那么
'a
生命周期是不必要的,在这种情况下你可以添加the compiler suggests绑定the compiler suggests: