我正在经历传奇的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
的函数,我相信这已经足以保证x
比y
更长,但我也在x
内加上对y
的引用,只是为了确保。
现在,f
中的约束使得此函数的调用不可能有效。我的意思是,它可以,当且仅当'x == 'y
,但它完全看起来x
的寿命严格超过y
,因为它在外部范围内定义。
尽管如此,这段代码还是会编译和编译。这怎么可能?
答案 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
子句中的边界。