我想编写一个函数A,该函数将一个函数B作为参数,该函数将一个由引用类型参数化的类型作为参数,该引用类型的生存期至少是A体内局部变量的生存期。
考虑以下示例:
struct Foo {}
fn consume(mut v: Vec<&Foo>) {
while let Some(..) = v.pop() {
// Do stuff
continue;
}
}
fn setup_and<F>(f: F)
where
F: FnOnce(&mut Vec<&Foo>) + Send,
{
let mut v: Vec<&Foo> = vec![];
let other_foo = Foo {};
f(&mut v);
v.push(&other_foo);
consume(v);
}
fn main() {
let foo = Foo {};
setup_and(|v| {
v.push(&foo);
});
}
rustc不能自行推断寿命。它抱怨:
error[E0597]: `foo` does not live long enough
--> src/main.rs:25:17
|
24 | setup_and(|v| {
| --- value captured here
25 | v.push(&foo);
| --------^^^-
| | |
| | borrowed value does not live long enough
| argument requires that `foo` is borrowed for `'static`
26 | });
27 | }
| - `foo` dropped here while still borrowed
我试图像这样为setup_and
指定的引用指定生存期:
fn setup_and<'a, F>(f: F)
where
F: FnOnce(&mut Vec<&'a Foo>) + Send,
{
let mut v: Vec<&'a Foo> = vec![];
现在rustc抱怨setup_and
本地引用other_foo
的寿命不足。我认为这是因为它要比setup_and
的范围更长的生存期。
在这种情况下,我将如何正确绑定生命周期?我想表示,引用必须在consume
调用结束之前一直有效。
答案 0 :(得分:3)
在实现过程中存在生命周期冲突,这是一个严重的问题,没有至少部分重新设计struct
和方法的外部签名的简单解决方案。它们全部来自setup_and
方法,当您明确描述生命周期界限时,编译器会突出显示它们。
您的方法的主体复制到下面,并带有注释以供您理解问题:
let mut v: Vec<&Foo> = vec![];
let other_foo = Foo {}; // other_foo is created here
f(&mut v);
v.push(&other_foo); // other_foo requires lifetime 'a to be added to this
consume(v); // consume does not restrict the lifetime requirement 'a
// other_foo is dropped here, at lifetime less than 'a
解决此问题的最简单方法是存储Arc<Foo>
,就像这样(playground):
fn setup_and<F>(f: F)
where
F: FnOnce(&mut Vec<Arc<Foo>>) + Send,
{
let mut v: Vec<Arc<Foo>> = vec![];
let other_foo = Foo {};
f(&mut v);
v.push(Arc::new(other_foo));
consume(&mut v);
}
Arc
是一个原子引用计数指针。它是一个可克隆的结构,用作指向堆上对象的动态指针。出于所有目的和目的,它可以作为只读参考,而无需使用期限。删除Arc
的所有副本时,其中的项目也将删除。
这解决了两个问题:
other_foo
现在已移入到Arc
中,并且不再引起生命周期问题Arc
实现Deref
)之所以选择Arc
是因为您的FnOnce
需要Send
,而Rc
(Arc
的单线程变体)无法提供。 / p>