此代码通过编译器(为了澄清生命周期,不会被忽略):
struct Foo<'a> {
_field: &'a i32,
}
fn test<'a, 'b, 'c>(_x: &'a mut Foo<'c>, _y: &'b bool) { // case 1
}
fn main() {
let f = &mut Foo { _field: &0 };
{
let p = false;
test(f, &p);
}
}
如果我在'b
的定义中使用'c
代替test
,请执行以下操作:
fn test<'a, 'b>(_x: &'a mut Foo<'b>, _y: &'b bool) { // case 2
}
代码无法编译(&#34; p活得不够长&#34;)!
在案例2的test
调用中,我期望发生的事情是:
'a
设置为f
的实际生命周期,'b
设置为Foo
的实际生命周期和&p
的实际生命周期的交集,即&p
&#39 ; s life,并且一切都应该没问题,如案例1所示。
相反,在案例2中实际上似乎发生的事情是'b
被迫成为Foo
的生命周期,这对&p
的生命周期来说太大了,因此编译器错误&#p; p的寿命不够长&#39;真?
更奇怪(案例3):如果test
采用&amp; mut,这只会失败。如果我离开<'b>
,请删除mut
,如下所示:
fn test<'a, 'b>(_x: &'a Foo<'b>, _y: &'b bool) { // case 3
}
代码再次传递。
有人对此有所了解吗?
干杯。
答案 0 :(得分:4)
注意与mut
的区别是一个重要的观察结果。我认为如果你改变第二个参数的类型并给出一个可能的实现会更有意义:
fn test<'a, 'b>(_x: &'a mut Foo<'b>, _y: &'b i32) {
_x._field = _y;
}
此功能可以改变_x
。该突变还包括在_field
中存储新的引用。但是,如果我们能够存储较短生命周期(您提到的交叉点)的引用,则只要内部块结束,Foo
中的引用就会变为无效,我们会违反Rust的内存安全保障!
当您使用不可变引用时,您不会有这种危险,因此编译器允许它。
你发现了一件重要的事情 - Rust并不总是关心你在函数中所做的事情。检查函数调用是否有效时,仅使用函数的类型签名。
我确定使用逆变和协方差之类的正确术语来说明这一点,但我不知道那些足够好,可以正确使用它们! ^ _ ^