简体   繁体   English

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

[英]Why Rust prevents from multiple mutable references?

Like in the topic, why Rust prevents from multiple mutable references?就像在主题中一样,为什么 Rust 会阻止多个可变引用? I have read chapter in rust-book, and I understand that when we have multi-threaded code we are secured from data races but let's look at this code:我已经阅读了 rust-book 中的章节,并且我知道当我们拥有多线程代码时,我们可以避免数据竞争,但让我们看一下这段代码:

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

    r1.insert(0, 'w');

}

This code is not running simultaneously so there is no possibility for data races.此代码不会同时运行,因此不会出现数据竞争。 What is more when I am creating new thread and I want to use variable from parent thread in a new thread I have to move it so only new thread is an owner of the parent variable.更重要的是,当我创建新线程并且我想在新线程中使用来自父线程的变量时,我必须移动它,所以只有新线程是父变量的所有者。

The only reason I can see is that programmer can lose himself in his code when it is growing up.我能看到的唯一原因是程序员在成长过程中会迷失在他的代码中。 We have multiple places in which one piece of data can be modified and even the code is not running parallel we can get some bugs.我们有多个地方可以修改一条数据,即使代码没有并行运行,我们也会遇到一些错误。

The fact that Rust prevent two mutable references at the same time to prevent data races is a common misconception. Rust 同时防止两个可变引用以防止数据竞争的事实是一个常见的误解。 This is only one of the reasons.这只是其中一个原因。 Preventing two mutable references makes it possible to keep invariants on types easily and let the compiler enforce that the invariant are not violated.防止两个可变引用可以轻松地保持类型上的不变量,并让编译器强制不违反不变量。

Take this piece of C++ code for an example:以这段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;
}

This is unsafe because you cannot mutate a vector while you are iterating it.这是不安全的,因为您不能在迭代向量时对其进行变异。 Mutating the vector might reallocate its internal buffer, which invalidates all references.变异向量可能会重新分配其内部缓冲区,这会使所有引用无效。 In C++, this is a UB.在 C++ 中,这是一个 UB。 In Python, Java or C# (and probably most other languages), you would get a runtime exception.在 Python、Java 或 C#(可能还有大多数其他语言)中,您会遇到运行时异常。

Rust however, prevents this kind of issues at compile time:然而,Rust 在编译时防止了这种问题:

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

gives an error:给出一个错误:

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

The big benefit of this restriction is that rust can prevent data races at compile time.这个限制的一大好处是 rust 可以防止编译时的数据竞争。 A data race occurs if we have two pointers pointing to the same piece of data and one of those pointers is used to write to the data and there is no mechanism to synchronize data access between those pointers.如果我们有两个指向同一块数据的指针并且其中一个指针用于写入数据并且没有同步这些指针之间的数据访问的机制,则会发生数据竞争。 In that situation, u could imagine one pointer will read the data and in the middle, another pointer modifying the data.在那种情况下,你可以想象一个指针将读取数据,而在中间,另一个指针将修改数据。 in that case, we are gonna get corrupted data back.在那种情况下,我们将恢复损坏的数据。 to fix this error you can switch these references back to be immutable references.要修复此错误,您可以将这些引用切换回不可变引用。

Rust enforces a “single writer or multiple readers” rule: either you can read and write the value, or it can be shared by any number of readers, but never both at the same time. Rust 强制执行“单个写入者或多个读取者”规则:您可以读取和写入该值,或者可以由任意数量的读取器共享,但不能同时进行。

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

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