在Rust中,当我们想要一个包含引用的结构时,我们通常会定义它们的生命周期:
struct Foo<'a> {
x: &'a i32,
y: &'a i32,
}
但是也可以为同一结构中的不同引用定义多个生命周期:
struct Foo<'a, 'b> {
x: &'a i32,
y: &'b i32,
}
什么时候这样做有用?有人可以提供一些示例代码,这些代码在生命周期为'a
时都不会编译,但在生命周期为'a
和'b
时会编译(反之亦然)吗?
答案 0 :(得分:13)
在熬夜之后,我能够想出一个生命时间重要的案例。这是代码:
static ZERO: i32 = 0;
struct Foo<'a, 'b> {
x: &'a i32,
y: &'b i32,
}
fn get_x_or_zero_ref<'a, 'b>(x: &'a i32, y: &'b i32) -> &'a i32 {
if *x > *y {
return x
} else {
return &ZERO
}
}
fn main() {
let x = 1;
let v;
{
let y = 2;
let f = Foo { x: &x, y: &y };
v = get_x_or_zero_ref(&f.x, &f.y);
}
println!("{}", *v);
}
如果您要将Foo
的定义更改为:
struct Foo<'a> {
x: &'a i32,
y: &'a i32,
}
然后代码将无法编译。
基本上,如果你想在任何需要它的参数具有不同生命周期的函数上使用struct的字段,那么struct的字段也必须具有不同的生命周期。
答案 1 :(得分:4)
这是另一个简单的示例,其中struct定义必须使用两个生存期才能按预期进行操作。它不会将聚合划分为不同生命周期的字段,而是将结构与另一个结构嵌套在一起。
struct X<'a>(&'a i32);
struct Y<'a, 'b>(&'a X<'b>);
fn main() {
let z = 100;
//taking the inner field out of a temporary
let z1 = ((Y(&X(&z))).0).0;
assert!(*z1 == z);
}
结构Y
有两个生存期参数,一个用于其包含的字段&X
,一个用于X
的包含字段&z
。
在操作((Y(&X(&z))).0).0
中,X(&z)
被创建为临时变量并被借用。它的生存期仅在此操作的范围内,在语句结束时到期。但是,由于X(&z)
的生存期与其包含的字段&z
不同,因此可以返回&z
进行操作,该值可以稍后在函数中访问。
如果对Y
结构使用单个生存期。该操作将不起作用,因为&z
的生存期与其包含的结构X(&z)
相同,并在语句末尾到期;因此返回的&z
不再有效,以后再访问。
请参阅playground中的代码。
答案 2 :(得分:2)
我想在这里重新回答我的问题,因为它仍然出现在搜索结果中的高位,我觉得我可以更好地解释。考虑以下代码:
struct Foo<'a> {
x: &'a i32,
y: &'a i32,
}
fn main() {
let x = 1;
let v;
{
let y = 2;
let f = Foo { x: &x, y: &y };
v = f.x;
}
println!("{}", *v);
}
和错误:
error[E0597]: `y` does not live long enough
--> src/main.rs:11:33
|
11 | let f = Foo { x: &x, y: &y };
| ^^ borrowed value does not live long enough
12 | v = f.x;
13 | }
| - `y` dropped here while still borrowed
14 | println!("{}", *v);
| -- borrow later used here
这是怎么回事?
f.x
的生命周期要求至少足够大以包含 x
的范围,直到 println!
语句(因为它使用 &x
和然后分配给v
)。Foo
的定义指定 f.x
和 f.y
使用相同的通用生命周期 'a
,因此 f.y
的生命周期必须至少为大到 f.x
。&y
分配给 f.y
,而 y
在 println!
之前超出了范围。错误!这里的解决方案是允许 Foo
为 f.x
和 f.y
使用单独的生命周期,我们使用多个通用生命周期参数来实现:
struct Foo<'a, 'b> {
x: &'a i32,
y: &'b i32,
}
现在 f.x
和 f.y
的生命周期不再联系在一起。编译器仍将使用在 println!
的 f.x
语句之前有效的生命周期。但是不再要求 f.y
使用相同的生命周期,因此编译器可以自由地为 f.y
选择更小的生命周期,例如仅对 y
的范围有效的生命周期.