在Rust中,当我们想要一个包含引用的结构时,我们通常会定义它们的生命周期:
struct Foo<'a> {
x: &'a i32,
y: &'a i32,
}
Run Code Online (Sandbox Code Playgroud)
但是也可以为同一结构中的不同引用定义多个生命周期:
struct Foo<'a, 'b> {
x: &'a i32,
y: &'b i32,
}
Run Code Online (Sandbox Code Playgroud)
什么时候这样做有用?有人可以提供一些示例代码,这些代码在两个生命周期都'a没有编译但是在生命周期时编译'a并且'b(反之亦然)?
Kai*_*Kai 20
我想在这里重新回答我的问题,因为它仍然出现在搜索结果中较高的位置,而且我觉得我可以更好地解释。考虑这段代码:
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);
}
Run Code Online (Sandbox Code Playgroud)
和错误:
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
Run Code Online (Sandbox Code Playgroud)
这里发生了什么?
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,
}
Run Code Online (Sandbox Code Playgroud)
f.x现在和的生命周期f.y不再联系在一起。编译器仍将使用在println!for 语句之前有效的生命周期f.x。但不再要求f.y使用相同的生存期,因此编译器可以自由地为 选择更小的生存期f.y,例如仅在 的范围内有效y。
Kai*_*Kai 15
在熬夜之后,我能够提出一个生命时间重要的案例.这是代码:
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);
}
Run Code Online (Sandbox Code Playgroud)
如果您要将此定义更改为Foo:
struct Foo<'a> {
x: &'a i32,
y: &'a i32,
}
Run Code Online (Sandbox Code Playgroud)
然后代码将无法编译.
基本上,如果要在任何需要它的参数具有不同生命周期的函数上使用结构的字段,那么结构的字段也必须具有不同的生命周期.
这是另一个简单的示例,其中结构体定义必须使用两个生命周期才能按预期运行。它不会将聚合拆分为不同生命周期的字段,而是将结构嵌套在另一个结构中。
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);
}
Run Code Online (Sandbox Code Playgroud)
该结构体Y有两个生命周期参数,一个用于其包含的字段&X,另一个用于X包含的字段&z。
在操作中((Y(&X(&z))).0).0,X(&z)作为临时创建并被借用。它的生命周期仅在此操作的范围内,在语句结束时到期。但是由于X(&z)的生命周期与其包含的字段不同&z,因此该操作可以很好地返回&z,其值可以稍后在函数中访问。
如果对Y结构使用单一生命周期。此操作将不起作用,因为 of 的生命周期&z与其包含的 struct 相同X(&z),在语句结束时到期;因此返回&z的不再有效,以后可以访问。
看到代码操场。