如何将引用生存期绑定到函数局部作用域

问题描述 投票:0回答:1

请考虑以下示例:

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调用结束之前必须一直有效。

rust
1个回答
0
投票

您在实现中存在生命周期冲突,这是一个严重的问题,没有至少部分重新设计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的所有副本时,其中的项目也将删除。

这解决了两个问题:

  1. 您的other_foo现在已移动到了Arc中,不再引起其生命周期问题
  2. 您现在可以像访问引用一样访问对象(Arc实现Deref
  3. 选择Arc是因为您的FnOnce需要Send,而RcArc的单线程变体)无法提供。

© www.soinside.com 2019 - 2024. All rights reserved.