tur*_*too 4 rust borrow-checker
在这个github讨论中,你会发现这个代码引起了借用检查器的愤怒:
fn main() {
let mut vec = vec!();
match vec.first() {
None => vec.push(5),
Some(v) => unreachable!(),
}
}
Run Code Online (Sandbox Code Playgroud)
我理解为什么在不可变借用突出的情况下进行突变是有问题的.我假设一个解决方案是明确地只有一个借用(一个可变的),但它仍然导致我有两个借款,一个不可变的借款,然后是一个可变的借款:
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!(),
}
}
Run Code Online (Sandbox Code Playgroud)
编译器仍然不满意:
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
Run Code Online (Sandbox Code Playgroud)
为什么我的解决方法不起作用,以及解决此问题的正确方法是什么?
你没有.好吧,你"避免"多次借款......没有多次借款.
fn main() {
let mut vec = vec![];
if vec.first().is_none() {
vec.push(5);
}
}
Run Code Online (Sandbox Code Playgroud)
更具有惯用力:
if vec.is_empty() {
vec.push(5);
}
Run Code Online (Sandbox Code Playgroud)
在这两种情况下,我们借用vec来进行方法调用,但在执行主体之前终止借用if.将其match与匹配头表达式中的借位进行比较,然后与匹配臂共享.
拿一个可以用于两种情况的可变借用
这不是它的工作原理.你必须了解记忆是如何发挥作用的,以及参考是什么.A Vec包含指向存储数据的存储器的指针.
当您获得向量的数据引用时,引用保存数据的内存地址,并且编译器确保只允许其中一个变异Vec.当您push有值时,可能需要分配新内存来存储所有数据.这可能会使您保留的引用无效.如果发生这种情况,那么下次使用该引用时,它将指向其他一些不相关的内存,您的程序将崩溃,您的用户数据将暴露于安全漏洞等等.等.
您链接的问题和相关的前RFC的整个要点是,此代码应该能够被确定为安全:
match vec.first() {
None => vec.push(5),
Some(v) => unreachable!(),
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下,程序员可以看到我们从不在这种情况下使用借位None,因此编译器理论上可以在执行任何匹配臂之前结束借用,或者使两个臂在生命周期中不相交.它现在不这样做.
但是,在您的代码版本中,它实际上更糟糕.通过明确地借入并将其保存在变量中,您可以延长借入需要保留多长时间,从而迫使它们重叠.
目前,唯一的解决方案是重新排序代码以人为限制借用.我在实践中并没有发现这非常烦人,因为通常有更好的代码组织.
也可以看看: