繁体   English   中英

为什么 Rust 会阻止多个可变引用?

[英]Why Rust prevents from multiple mutable references?

就像在主题中一样,为什么 Rust 会阻止多个可变引用? 我已经阅读了 rust-book 中的章节,并且我知道当我们拥有多线程代码时,我们可以避免数据竞争,但让我们看一下这段代码:

fn main() {
    let mut x1 = String::from("hello");
    let r1 = &mut x1;
    let r2 = &mut x1;

    r1.insert(0, 'w');

}

此代码不会同时运行,因此不会出现数据竞争。 更重要的是,当我创建新线程并且我想在新线程中使用来自父线程的变量时,我必须移动它,所以只有新线程是父变量的所有者。

我能看到的唯一原因是程序员在成长过程中会迷失在他的代码中。 我们有多个地方可以修改一条数据,即使代码没有并行运行,我们也会遇到一些错误。

Rust 同时防止两个可变引用以防止数据竞争的事实是一个常见的误解。 这只是其中一个原因。 防止两个可变引用可以轻松地保持类型上的不变量,并让编译器强制不违反不变量。

以这段C++代码为例:

#include <vector>

int main() {
    std::vector<int> foo = { 1, 2, 3 };
    
    for (auto& e: foo) {
        if (e % 2 == 0) {
            foo.push_back(e+1);
        }
    }

    return 0;
}

这是不安全的,因为您不能在迭代向量时对其进行变异。 变异向量可能会重新分配其内部缓冲区,这会使所有引用无效。 在 C++ 中,这是一个 UB。 在 Python、Java 或 C#(可能还有大多数其他语言)中,您会遇到运行时异常。

然而,Rust 在编译时防止了这种问题:

fn main() {
    let mut foo = vec![1, 2, 3];
    
    for e in foo {
        if e % 2 == 0 {
            foo.push(e+1);
        }
    }
}

给出一个错误:

error[E0382]: borrow of moved value: `foo`
 --> src/main.rs:6:13
  |
2 |     let mut foo = vec![1, 2, 3];
  |         ------- move occurs because `foo` has type `std::vec::Vec<i32>`, which does not implement the `Copy` trait
3 |     
4 |     for e in foo {
  |              ---
  |              |
  |              value moved here
  |              help: consider borrowing to avoid moving into the for loop: `&foo`
5 |         if e % 2 == 0 {
6 |             foo.push(e+1);
  |             ^^^ value borrowed here after move

这个限制的一大好处是 rust 可以防止编译时的数据竞争。 如果我们有两个指向同一块数据的指针并且其中一个指针用于写入数据并且没有同步这些指针之间的数据访问的机制,则会发生数据竞争。 在那种情况下,你可以想象一个指针将读取数据,而在中间,另一个指针将修改数据。 在那种情况下,我们将恢复损坏的数据。 要修复此错误,您可以将这些引用切换回不可变引用。

Rust 强制执行“单个写入者或多个读取者”规则:您可以读取和写入该值,或者可以由任意数量的读取器共享,但不能同时进行。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM