此代码通过编译器(为了澄清生命周期,不会被忽略):
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);
}
}
如果我在 test
的定义中使用 'b
而不是 'c
,如下所示:
fn test<'a, 'b>(_x: &'a mut Foo<'b>, _y: &'b bool) { // case 2
}
代码无法编译(“p不能长寿”)!
在案例2的 test
调用中我期望发生的事情是:
-
'a
设置为f
的实际生命周期, -
'b
被设置为Foo
的实际生命周期和&p
的实际生命周期的交集,这是&p
的生命周期,
一切都应该没问题,如案例1所示 .
相反,在案例2中实际上似乎发生的事情是 'b
被迫成为 Foo
的生命周期,这对于 &p
来说太大了's lifetime, hence the compiler error ' p不能长寿 . 真正?
甚至更陌生(案例3):如果 test
采用&mut,这只会失败 . 如果我留下 <'b>
,但删除 mut
如下:
fn test<'a, 'b>(_x: &'a Foo<'b>, _y: &'b bool) { // case 3
}
代码再次传递 .
谁有人对此有所了解?
干杯 .
1 回答
注意与
mut
的区别是一个关键的观察 . 我认为如果你改变第二个参数的类型并给出一个可能的实现会更有意义:此函数具有变异
_x
的能力 . 该突变还包括在_field
中存储新引用 . 但是,如果我们能够存储具有 shorter 生命周期的引用(您提到的交叉点),则一旦内部块结束,Foo
中的引用将变为无效,我们将违反Rust的内存安全保证!当您使用不可变引用时,您没有这种危险,因此编译器允许它 .
你发现了一件重要的事情 - Rust并不总是关心你在函数中做了什么 . 检查函数调用是否有效时,仅使用函数的类型签名 .
我使用正确的术语,如逆变和协方差,这是一种奇特的说法,但我不太清楚它们是否正确使用它们! ^ _ ^