Stu*_*t4K 1 reference mutability rust borrow-checker borrowing
该锈书大约有多个读者和多个可变对象引用的数据竞争情况,可能会导致问题进行会谈。
例如,这段代码:
fn main() {
let mut x = 1;
let r1 = &mut x;
*r1 = 2;
let r2 = &mut x;
*r2 = 3;
println!("{}", r1);
println!("{}", r2);
}
Run Code Online (Sandbox Code Playgroud)
将被 Rust 编译器拒绝,因为r1和r2作用域交织在一起。
但是这里有什么问题呢?我的意思是,这只是一个线程,没有“同时读取和写入”,因此所有这些语句都应严格按顺序执行并给出确定性的可重现结果。
我经常认为,虽然技术意义上的数据竞争只能发生在并行系统中,但感觉很像数据竞争的问题总是在顺序系统中出现。一个例子是 C++ 民间所说的迭代器失效——基本上,如果你在一个哈希表上迭代并且你试图在迭代期间修改哈希表,你会得到未定义的行为。有时您的迭代会跳过键或值,有时它会向您显示新键,有时则不会,等等。
但无论结果如何,迭代器失效感觉与数据竞争非常相似。问题经常出现,因为您有一段代码迭代哈希表,然后调用在其他模块中定义的子例程。然后这个其他模块写入同一个哈希表。两个模块本身看起来都不错,只是两者的结合导致了问题。并且由于结果的未定义性质,经常发生代码可以正常工作很长时间——直到它不能正常工作。
Rust 的类型系统可以防止迭代器失效。
Rust 的类型系统不允许像下面这样的单线程程序进行编译,因为它们会导致未定义的行为,虽然从技术上讲这不是数据竞争,但这个特定的错误与“由两个独立的代码段变异引起的错误相同”以交织的方式使用相同的数据”,因此它与数据竞赛非常相似,我相信这就是 Rust 书试图传达的内容:
use std::collections::HashMap;
fn main() {
let mut map = HashMap::new();
map.insert(1, 1);
map.insert(2, 2);
map.insert(3, 3);
for _ in map.iter() {
map.insert(4, 4); // compile error!
}
}
Run Code Online (Sandbox Code Playgroud)