此代码未通过可怕的借用检查程序(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());
}
错误:
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
有人可以解释为什么会这样吗?当dat
返回时,我会认为reference_to_a()
的可变借位被转换为不可变的,因为该函数只返回一个不可变引用。借用检查员还不够聪明吗?这是计划好的吗?有办法吗?
答案 0 :(得分:4)
生命期与参考是否可变是分开的。完成代码:
fn reference_to_a(&mut self) -> &i32
虽然生命周期已被省略,但这相当于:
fn reference_to_a<'a>(&'a mut self) -> &'a i32
即。输入和输出的寿命是相同的。这是将生命周期分配给这样一个函数的唯一方法(除非它返回&'static
对全局数据的引用),因为你无法从零构成输出生命周期。
这意味着如果您通过将返回值保存在变量中来保持返回值,那么您也可以使&mut self
保持活动状态。
另一种思考方式是&i32
是&mut self
的子借位,因此只有在到期之前才有效。
正如@aSpex指出的那样,这是covered in the nomicon。
答案 1 :(得分:0)
为什么会出错: 尽管2.5年前@Chris已经给出了更精确的解释,但您可以阅读fn reference_to_a(&mut self) -> &i32
作为声明
“我想独占借用
self
,然后返回一个共享的/不可变的引用,该引用的生存期与原始独占借用时间一样长” (source) < / sub>
显然it can even prevent me from shooting myself in the foot。
借阅检查器是否还不够聪明?这是计划好的吗?
仍然无法表达“我想在通话期间专门借用自己,并返回具有单独生命期的共享引用”。正如@aSpex所指出的那样,它是mentioned in the nomicon,并且在2018年末被列在Things Rust doesn’t let you do中。
如先前的other borrow checker improvements were deemed higher priority一样,我找不到解决该问题的具体计划。允许使用单独的读/写“生命周期角色”(Ref2<'r, 'w>
)的想法是mentioned in the NLL RFC,但据我所知,没有人将其变成自己的RFC。
有没有解决的办法? 并非如此,但是首先要根据您需要这样做的原因,可能需要采用其他方式来构造代码:
fn(&mut self) -> &T
分成两部分,一个取&mut self
,另一个返回&T
,as suggested by @Chris here fn(&mut self) -> (&Self, &T)
(from this answer)&self
引用并使用interior mutability(即,定义Self
中需要突变为Cell<T>
或{{1 }})。这可能看起来像作弊,但这实际上是适当的,例如需要implementation detail of a logically-immutable method作为可变性的原因。毕竟,我们要使方法RefCell<T>
not because it mutates parts of self
, but到make it known to the caller so that it's possible to reason about which values can change in a complex program。