我很难理解为什么Rust的借用检查器不允许多个可变借用,而这样做是安全的。
让我们给予一个例子:
fn borrow_mut(s : &mut String) {
s.push_str(" world!");
println!("{}", s);
}
fn main() {
let mut s = String::from("hello");
let rs : &mut String = &mut s;
// second mutable borrow
borrow_mut(&mut s);
println!("{rs}");
}
此代码无法编译,并显示以下消息:
error[E0499]: cannot borrow `s` as mutable more than once at a time
--> main.rs:11:16
|
8 | let rs : &mut String = &mut s;
| ------ first mutable borrow occurs here
...
11 | borrow_mut(&mut s);
| ^^^^^^ second mutable borrow occurs here
12 |
13 | println!("{rs}");
| -- first borrow later used here
rs
指向堆栈帧中String
类型的变量。String
包含堆中内存的指针。因此,即使字符串在borrow_mut()
中重新分配其数据,两个指针仍然有效,因此这段代码应该是安全的。
有人能解释为什么借入检查器阻止多个可变借入,即使它是安全的吗?
1条答案
按热度按时间dtcbnfnu1#
这是为了线程安全,以避免数据竞争。如果两个这样的可变借用可以存在,那么两个执行线程都可以尝试修改原始数据。如果它们这样做,各种各样的恶劣竞争条件可能会出现,例如,如果两个线程都试图追加到字符串:
借用作为一种语言特性意味着函数可以暂时将其唯一的可变所有权移交给其他函数;而另一个函数持有借位,则原始对象不能通过 * 除了 * 可变借位之外任何东西来访问。这还意味着对于不可变借位,它可以防止可变借位,后者可能会导致不可变借位的读操作和可变借位的写操作之间的竞争。借位检查器阻止您启动修改
s
的线程,然后从主线程调用borrow_mut
,当两个线程同时修改s
时,它们产生垃圾或使程序崩溃。需要说明的是,在Rust的某个未来版本中,通过一个高级的借用检查器,这段代码 * 可以 * 工作(您编写的代码本质上不会做任何不安全的事情)。但是完全分析深层代码路径以确保不会发生任何不安全的事情是很困难的,相对来说,要制定更严格的规则(如果他们确信它不会对语言设计施加限制,那么将来可能会放松限制)。如果将已有的一个可变借位传递到
borrow_mut
中,代码就可以正常工作;您的代码不会因为采用RustWay ™而变得更糟。