向矢量添加临时值时的生命周期

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

我在尝试理解Rust生命周期在某些情况下如何工作时遇到了一些问题,如下所示。我不能让它工作,但我不知道为什么。

struct Bar {
    value: &'static str,
}

struct Foo<'a, T: 'a> {
    bar: &'a T,
}

fn main() {
    let mut foos = Vec::new();

    let y = Bar {
        value: "Hello, world!",
    };
    let x = Foo { bar: &y };

    foos.push(x);
}
error[E0597]: `y` does not live long enough
  --> src/main.rs:15:25
   |
15 |     let x = Foo { bar: &y };
   |                         ^ borrowed value does not live long enough
...
18 | }
   | - `y` dropped here while still borrowed
   |
   = note: values in a scope are dropped in the opposite order they are created

这是我实际尝试实现的简化示例:

fn main() {
    let foos = vec![
        Foo { bar: &(Bar { value: "a" }) },
        Foo { bar: &(Bar { value: "b" }) },
    ];
}

我很欣赏任何想法,想法或解释。

rust lifetime
1个回答
1
投票

After Non-Lexical Lifetimes

由于non-lexical lifetimes,您的代码的两个版本现在都可以使用。

Before Non-Lexical Lifetimes

您的问题可以简化为此示例:

fn main() {
    let mut foos = Vec::new();
    let y = &42;
    foos.push(y);
}

在这种情况下要记住的重要事项是变量以它们创建的相反顺序被销毁。您几乎可以将代码视为

fn main() {
    let mut foos = Vec::new();
    {
        let y = &42;
        {
            foos.push(y);
        }
        // destroy y
    }}
    // destroy foos
}

对于我正在展示的简单值,这并不重要,但是当您拥有具有自定义Drop实现的复杂类型时,它更为重要。

一个简单的解决方法是重新排序语句:

fn main() {
    let y = &42;
    let mut foos = Vec::new();
    foos.push(y);
}

现在,它保证被引用的东西比存储在向量中的引用更长。对于原始简化示例,这适用于:

let y = Bar { value: "Hello, world!" };
let x = Foo { bar: &y };
let mut foos = Vec::new();
foos.push(x);

您的原始代码有点棘手的问题。让我们来看看vec!宏的扩展:

let foos = <[_]>::into_vec(Box::new([Foo { bar: &(Bar { value: "a" }) }]));

我们可以简化到哪个

let foos = Box::new(&42);

问题是临时变量是暂时的。它仅在函数调用期间存在。这意味着对临时变量的引用不能持续更长时间。这就是为什么错误消息表明“考虑使用let绑定来增加其寿命”。通过这样做,变量将比函数调用更长寿。

是否可以在不使用let语句的情况下使临时值持续更长时间?向量将有许多值,比如30。所以我必须放置30个let语句?

不,你必须明确他们应该活多久,所以你需要明确他们在哪里。我看到两个解决方案:

  1. 更改您的结构,以便他们拥有项目,而不是引用它们: struct Foo<T> { bar: T, } let foos = vec![ Foo { bar: Bar { value: "a" } }, Foo { bar: Bar { value: "b" } }, ];
  2. 创建一个拥有所有内部类型的向量,然后映射它以获取引用: let bars = vec![Bar { value: "a" }, Bar { value: "b" }]; let foos: Vec<_> = bars.iter().map(|bar| Foo { bar: bar }).collect();
© www.soinside.com 2019 - 2024. All rights reserved.