向向量添加临时值时的生命周期
Lifetimes when adding temporary values to vectors
我在尝试了解 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" }) },
];
}
如果有任何想法、想法或解释,我将不胜感激。
非词法生命周期后
由于 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);
问题是临时变量是临时。它仅在函数调用期间存在。这意味着对临时变量的引用不能持续更长时间。这就是错误消息提示 "consider using a let
binding to increase its lifetime" 的原因。通过这样做,变量将比函数调用的寿命更长。
Is it possible to make the temporary value last longer without using a let statement? The vector will have many values, say 30. So I'll have to place 30 let statements?
不,你必须明确他们应该活多久,所以你需要明确他们在哪里。我看到两个解决方案:
更改您的结构,使其拥有项目,而不是引用它们:
struct Foo<T> {
bar: T,
}
let foos = vec![
Foo { bar: Bar { value: "a" } },
Foo { bar: Bar { value: "b" } },
];
创建一个拥有所有内部类型的向量,然后对其进行映射以获取引用:
let bars = vec![Bar { value: "a" }, Bar { value: "b" }];
let foos: Vec<_> = bars.iter().map(|bar| Foo { bar: bar }).collect();
我在尝试了解 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" }) },
];
}
如果有任何想法、想法或解释,我将不胜感激。
非词法生命周期后
由于 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);
问题是临时变量是临时。它仅在函数调用期间存在。这意味着对临时变量的引用不能持续更长时间。这就是错误消息提示 "consider using a let
binding to increase its lifetime" 的原因。通过这样做,变量将比函数调用的寿命更长。
Is it possible to make the temporary value last longer without using a let statement? The vector will have many values, say 30. So I'll have to place 30 let statements?
不,你必须明确他们应该活多久,所以你需要明确他们在哪里。我看到两个解决方案:
更改您的结构,使其拥有项目,而不是引用它们:
struct Foo<T> { bar: T, } let foos = vec![ Foo { bar: Bar { value: "a" } }, Foo { bar: Bar { value: "b" } }, ];
创建一个拥有所有内部类型的向量,然后对其进行映射以获取引用:
let bars = vec![Bar { value: "a" }, Bar { value: "b" }]; let foos: Vec<_> = bars.iter().map(|bar| Foo { bar: bar }).collect();