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

问题描述 投票:1回答:1
  1. 第一个问题来自主题,为什么Rust阻止了多个可变引用?我已经阅读了rust-book中的一章,并且我了解到,当我们拥有多线程代码时,我们就可以避免数据竞争,但让我们看看下面的代码:
fn main() {
    let mut x1 = String::from("hello");
    let r1 = &mut x1;
    let r2 = &mut x1;

    r1.insert(0, 'w');

}

此代码无法同时运行,因此不会发生数据争用。当我创建新线程并且要在新线程中使用父线程中的变量时,还需要移动它,因此只有新线程才是父变量的所有者。

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

  1. 为什么允许这样做:
fn main() {
    let mut w = MyStruct;
    w.fun1();
}

struct MyStruct;

impl MyStruct {
    fn fun1(&mut self) {
        self.fun2();
    }

    fn fun2(&mut self) {
        println!("Hello world 2");
    }
}

在上面的代码中,fun1()获取mut MyStruct并也使用mut MyStruct调用fun2()。它是在一个范围内双重可变引用吗?

multithreading rust borrow-checker borrowing
1个回答
0
投票

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#(可能还有大多数其他语言)中,您将获得运行时异常。

但是,在编译时避免出现此类问题:

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
© www.soinside.com 2019 - 2024. All rights reserved.