簡體   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