更新时间:2023-09-08 22:58:52
生命周期与引用是否可变是分开的.完成代码:
fn reference_to_a(&mut self) ->&i32
虽然生命周期已被省略,但这相当于:
fn reference_to_a(&'a mut self) ->&'a i32
即输入和输出的生命周期是一样的.这是为这样的函数分配生命周期的唯一方法(除非它返回一个对全局数据的 &'static
引用),因为你不能从零开始构成输出生命周期.
这意味着如果您通过将返回值保存在变量中来使其保持活动状态,那么您也会使 &mut self
保持活动状态.
另一种思考方式是 &i32
是 &mut self
的子借用,因此仅在到期之前有效.>
正如@aSpex 所指出的,这是在 nomicon 中涵盖的内容.
This code fails the dreaded borrow checker (playground):
struct Data {
a: i32,
b: i32,
c: i32,
}
impl Data {
fn reference_to_a(&mut self) -> &i32 {
self.c = 1;
&self.a
}
fn get_b(&self) -> i32 {
self.b
}
}
fn main() {
let mut dat = Data{ a: 1, b: 2, c: 3 };
let aref = dat.reference_to_a();
println!("{}", dat.get_b());
}
Since non-lexical lifetimes were implemented, this is required to trigger the error:
fn main() {
let mut dat = Data { a: 1, b: 2, c: 3 };
let aref = dat.reference_to_a();
let b = dat.get_b();
println!("{:?}, {}", aref, b);
}
Error:
error[E0502]: cannot borrow `dat` as immutable because it is also borrowed as mutable
--> <anon>:19:20
|
18 | let aref = dat.reference_to_a();
| --- mutable borrow occurs here
19 | println!("{}", dat.get_b());
| ^^^ immutable borrow occurs here
20 | }
| - mutable borrow ends here
Why is this? I would have thought that the mutable borrow of dat
is converted into an immutable one when reference_to_a()
returns, because that function only returns an immutable reference. Is the borrow checker just not clever enough yet? Is this planned? Is there a way around it?
Lifetimes are separate from whether a reference is mutable or not. Working through the code:
fn reference_to_a(&mut self) -> &i32
Although the lifetimes have been elided, this is equivalent to:
fn reference_to_a<'a>(&'a mut self) -> &'a i32
i.e. the input and output lifetimes are the same. That's the only way to assign lifetimes to a function like this (unless it returned an &'static
reference to global data), since you can't make up the output lifetime from nothing.
That means that if you keep the return value alive by saving it in a variable, you're keeping the &mut self
alive too.
Another way of thinking about it is that the &i32
is a sub-borrow of &mut self
, so is only valid until that expires.
As @aSpex points out, this is covered in the nomicon.