“寿命”关系和实际范围

时间:2016-01-27 23:28:11

标签: rust lifetime

我正在经历传奇的RFC 1214,似乎我错过了一些至关重要的东西。

struct Foo;

struct Bar<'a> {
   foo: &'a Foo
}


fn f<'x, 'y>(_: &'x Foo, _: &'y Bar<'x>)
     where 'y: 'x, 'x: 'y {
}

fn g<'x>(x: &'x Foo) {
   let y = Bar {foo : x};
   f(x, &y);  // ?
}


fn main(){
   let x = Foo;
   g(&x);
}

在此代码中,我竭尽全力确保'x : 'y 'y : 'x。定义x的函数调用定义y的函数,我相信这已经足以保证xy更长,但我x内加上对y的引用,只是为了确保。

现在,f中的约束使得此函数的调用不可能有效。我的意思是,它可以,当且仅当'x == 'y,但它完全看起来x的寿命严格超过y,因为它在外部范围内定义。

尽管如此,这段代码还是会编译和编译。这怎么可能?

2 个答案:

答案 0 :(得分:7)

生命周期有variance,也就是说,编译器可以选择将&'a Foo的生命周期缩短到某些&'b Foo。这样的引用的生命周期意味着Foo至少与'a一样长:更短的生命周期仍然满足此保证。这就是这里发生的事情:'x生命周期缩短为与&y引用具有相同的生命周期。

您可以使用不变性来停止此编译:如果无法缩短生命周期'x,则代码将按预期停止编译。

use std::cell::Cell;

struct Foo;

struct Bar<'a> {
   foo: Cell<&'a Foo>
}


fn f<'x, 'y>(_: Cell<&'x Foo>, _: &'y Bar<'x>)
     where 'y: 'x, 'x: 'y {
}

fn g<'x>(x: Cell<&'x Foo>) {
   let y = Bar {foo : x.clone()};
   f(x, &y);  // ?
}


fn main(){
   let x = Foo;
   g(Cell::new(&x));
}
<anon>:16:10: 16:11 error: `y` does not live long enough
<anon>:16    f(x, &y);  // ?
                   ^
<anon>:14:28: 17:2 note: reference must be valid for the lifetime 'x as defined on the block at 14:27...
<anon>:14 fn g<'x>(x: Cell<&'x Foo>) {
<anon>:15    let y = Bar {foo : x.clone()};
<anon>:16    f(x, &y);  // ?
<anon>:17 }
<anon>:15:34: 17:2 note: ...but borrowed value is only valid for the block suffix following statement 0 at 15:33
<anon>:15    let y = Bar {foo : x.clone()};
<anon>:16    f(x, &y);  // ?
<anon>:17 }

这里发生的事情Cell<T>T中是不变的,因为它是可读写的。这尤其意味着Cell<&'x Foo>无法缩短为Cell<&'y Foo>:使用真正&'y Foo的引用'y填充它(即仅持续'y)将表示一旦单元格离开'y(但仍在'x中),引用就会悬空。

答案 1 :(得分:5)

以下三项内容可以解释您所看到的行为:

  • 'x上的f是与'x中的g完全不同的独立生命周期参数。编译器可以选择不同的具体生命周期来替换每个生命周期。
  • 'x : 'y, 'y: 'x表示'x == 'y(这不是真正的语法)。
  • 如果您有参考,则可以隐式创建另一个更短生命周期的参考。考虑例如函数fn mangle_a_string<'a>(_s: &'a str) -> &'a str { "a static string" }

所以f(x, &y)中发生的事情是第一个参数被强制转换为生命周期较短的引用,匹配第二个参数的lifetim,以满足where子句中的边界。