在this github discussion中,您会发现此代码引起借阅检查器的愤怒:
fn main() {
let mut vec = vec!();
match vec.first() {
None => vec.push(5),
Some(v) => unreachable!(),
}
}
我理解为什么在不可变借用突出的情况下进行突变是有问题的。我假设一个解决方案是明确只有一个借(一个可变的),但它仍然导致我有两个借款,一个不可变的借款,然后是一个可变的借款:
fn main() {
let mut vec: Vec<i32> = vec!();
let r_vec: &mut Vec<i32> = &mut vec;
match r_vec.first() {
None => r_vec.push(5),
Some(v) => unreachable!(),
}
}
编译器仍然不满意:
error[E0502]: cannot borrow `*r_vec` as mutable because it is also borrowed as immutable
--> testrust.rs:7:17
|
6 | match r_vec.first() {
| ----- immutable borrow occurs here
7 | None => r_vec.push(5),
| ^^^^^ mutable borrow occurs here
8 | Some(v) => unreachable!(),
9 | }
| - immutable borrow ends here
为什么我的解决方法不起作用,解决此问题的正确方法是什么?
答案 0 :(得分:6)
你没有。好吧,你“避免”多次借款......没有多次借款。
fn main() {
let mut vec = vec![];
if vec.first().is_none() {
vec.push(5);
}
}
更具有惯用力:
if vec.is_empty() {
vec.push(5);
}
在这两种情况下,我们借用vec
来进行方法调用,但在执行if
的主体之前终止借用。将其与匹配头表达式中借用的match
进行比较,然后与匹配臂共享。
取一个可用于两种情况的可变借用
这不是它的工作原理。你必须了解记忆是如何发挥作用的,以及参考是什么。 Vec
包含指向存储数据的内存的指针。
当你获得向量的数据引用时,引用保存数据的内存地址,编译器确保只有一个允许变异Vec
。当您push
一个值时,可能需要分配新内存来存储所有数据。这可能会使您保留的引用无效。如果发生这种情况,那么下次使用该引用时,它将指向其他一些不相关的内存,您的程序将崩溃,您的用户数据将暴露于安全漏洞等等。
issue you linked和相关pre-RFC的全部内容是此代码应能够被确定为安全:
match vec.first() {
None => vec.push(5),
Some(v) => unreachable!(),
}
在这种情况下,程序员可以看到我们从不在None
情况下使用借位,因此编译器理论上可以在执行任何匹配臂之前结束借用,否则会使两个臂脱离尊重生命。 现在不这样做。
但是,在您的代码版本中,实际上更糟。通过明确地借入并将其保存在变量中,您可以延长借入需要保留多长时间,从而迫使它们重叠。
目前,唯一的解决方案是重新排序代码以人为限制借用。我在实践中并没有发现这非常烦人,因为通常会有更好的代码组织。
另见: