Тот факт, что 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