Почему Rust предотвращает множественные изменяемые ссылки? - PullRequest
2 голосов
/ 13 октября 2019

Как и в теме, почему Rust предотвращает множественные изменяемые ссылки? Я прочитал главу в Rust-Book, и я понимаю, что, когда у нас есть многопоточный код, мы защищены от скачек данных, но давайте посмотрим на этот код:

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

    r1.insert(0, 'w');

}

Этот код не выполняется одновременно, поэтомунет возможности для гонок данных. Более того, когда я создаю новую нить и хочу использовать переменную из родительской нити в новой нити, я должен переместить ее, чтобы только новая нить являлась владельцем родительской переменной.

Единственная причина, которую я вижу, состоит в том, что программист может потерять себя в своем коде, когда он растет. У нас есть несколько мест, в которых можно изменить один фрагмент данных, и даже если код не работает параллельно, мы можем получить некоторые ошибки.

1 Ответ

6 голосов
/ 13 октября 2019

Тот факт, что 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...