此代码工作正常(Playground):
struct F<'a> {
x: &'a i32,
}
impl<'a> F<'a> {
fn get<'b>(&'b self) -> &'a i32 {
self.x
}
}
fn main() {
let x = 3;
let y = F { x: &x };
let z = y.get();
}
但是,当我改变x
是一个可变的引用,而不是(Playground):
struct Foo<'a> {
x: &'a mut i32, // <-- `mut` added
}
impl<'a> Foo<'a> {
fn get(&self) -> &'a i32 {
self.x
}
}
fn main() {
let mut x = 3; // <-- `mut` added
let y = Foo { x: &mut x }; // <-- `mut` added
let z = y.get();
}
我得到这个错误:
error[E0312]: lifetime of reference outlives lifetime of borrowed content...
--> src/main.rs:7:9
|
7 | self.x
| ^^^^^^
|
note: ...the reference is valid for the lifetime 'a as defined on the impl at 5:6...
--> src/main.rs:5:6
|
5 | impl<'a> Foo<'a> {
| ^^
note: ...but the borrowed content is only valid for the anonymous lifetime #1 defined on the method body at 6:5
--> src/main.rs:6:5
|
6 | / fn get(&self) -> &'a i32 {
7 | | self.x
8 | | }
| |_____^
为什么会这样?据我看到它,避谈寿命发生了变化:所有值/引用仍然为万岁正是因为在第一个代码段。
为什么锈编译器拒绝这个实施get
的?因为它允许:
下面是一个完全合理的main
,假设get
编译:
fn main() {
let mut x = 3;
let y = Foo { x: &mut x };
let a = y.get();
let b = y.x;
println!("{} {}", a, b);
}
然而,如果get
是编译,这将是罚款:
a
不借用y
b
“消耗” y
(从y.x
移动),但之后我们不重用所以,一切都很好,除了我们现在有一个&i32
和&mut i32
都指向x
。
注:既要编译,你可以使用unsafe
get
内:unsafe { std::mem::transmute(&*self.x) }
;可怕的,不是吗?
在借检查算法的心脏是在其锈病的存储安全建立的基石:
别名XOR可变性
锈病保证,只要你正在修改的东西,没有观察者可以有一些可能成为里面晃来晃去的参考实现存储安全无垃圾收集。
这一点,在转弯,让我们解释:
&T
作为混叠参考;它是Copy
&mut T
作为唯一的参考;它不是Copy
,因为这将违反唯一性,但它可以移动这种差异在这里救了我们。
由于&mut T
不能被复制,只有这样,才能从&mut T
去&T
(或&mut T
)是执行重新借用:解引用并采取到结果的引用。
这是由编译器隐式进行。做手工做的稍微好一些错误信息:
fn get<'b>(&'b self) -> &'a i32 {
&*self.x
}
error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements --> <anon>:7:9 | 7 | &*self.x | ^^^^^^^^ | help: consider using an explicit lifetime parameter as shown: fn get(&'a self) -> &'a i32 --> <anon>:6:5 | 6 | fn get<'b>(&'b self) -> &'a i32 { | ^
为什么不能推断一辈子?因为再借的使用寿命是有限的'b
但我们需要'a
并有两者之间没有任何关系!
顺便说一句,这是自摆乌龙节省了我们这里,因为它确保了实例Foo
必须借用而导致生活(阻止我们使用通过Foo::x
一个可变参考)。
继编译器提示,并返回&'b i32
作品...并防止上述main
从编译:
impl<'a> Foo<'a> {
fn get<'b>(&'b self) -> &'b i32 {
&*self.x
}
}
fn main() {
let mut x = 3;
let y = Foo { x: &mut x };
let a = y.get();
let b = y.x;
println!("{} {}", a, b);
}
error[E0505]: cannot move out of `y.x` because it is borrowed --> <anon>:16:9 | 15 | let a = y.get(); | - borrow of `y` occurs here 16 | let b = y.x; | ^ move out of `y.x` occurs here
但是它可以让第一main
编译没有问题:
fn main() {
let mut x = 3;
let y = Foo { x: &mut x };
let z = y.get();
println!("{}", z);
}
打印3
。