【发布时间】:2021-08-10 09:29:41
【问题描述】:
在下面的代码中,我试图了解通用生命周期参数'a 是如何专门化的。
struct Wrapper<'a>(&'a i32);
fn foo() {
let mut r;
{
let x = 0; // the lifetime of x, call it 'x, starts from here |
r = Wrapper(&x); // 'a parameter in Wrapper is specialized to 'x |
drop(r); // |
} // --------------------------------- 'x ends here |
{
let y = 0; // the lifetime of y, call it 'y, starts from here |
// 'y is distinct from 'x |
// neither outlives the other one |
r = Wrapper(&y); // why 'a parameter can again be specialized to 'y? |
drop(r); // |
} // ------------------------------------ 'y ends here |
}
为什么一个通用生命周期参数 'a 可以专门化为两个不相交的生命周期 'x 和 'y,用于一个对象 'r?
换个角度看,我对r的具体类型很困惑。从 Rustonomicon 的 subtyping and variance 章节中,我了解到生命周期 'a 是泛型类型 Wrapper<'a> 的一部分。当泛型被特化时,它不能是Wrapper<'x> 也不能是Wrapper<'y>。那么r的类型是什么?
也许higher-rank trait bound与它有关?
如果有人能解释一下 Rust 编译器是如何在内部解释这一点的,我将不胜感激。
更新:
现有答案表明r 的生命周期可以有多个起点和终点。如果这是真的,那么'r 是'x 和'y 的联合。但是,这种解释并不适合subtyping 规则。例如,考虑下面的代码,'r2 和 'r 都不是另一个的子类型(或寿命更长),所以我们应该不能调用bar(r, r2),但实际上可以。矛盾。
struct Wrapper<'a>(&'a i32);
fn bar<'a>(_p: Wrapper<'a>, _q: Wrapper<'a>) {}
fn foo() {
let mut r;
{
let z = 0;
let r2 = Wrapper(&z); // -> |
{ // |
let x = 0; // -> | // +--'r2
r = Wrapper(&x); // |--'x--+ // |
bar(r, r2); // | | // <- |
} // <- | |
} // |
{ // +--'r
let y = 0; // -> | |
r = Wrapper(&y); // |--'y--+
drop(r); // |
} // <- |
}
【问题讨论】:
-
Rustonomicon 有一个标题为The area covered by a lifetime 的部分,其中指出:“一生可以有一个停顿。或者您可能会将其视为两个不同的借用,只是被绑定到同一个局部变量。”