为什么Arc和Mutex允许我更改不可变变量的值?

时间:2016-04-21 15:19:45

标签: rust

举个例子:

fn main() {
    let dato = std::sync::Arc::new(std::sync::Mutex::new(1u8));

    for _ in 0..3 {
        let value = dato.clone();

        std::thread::spawn(move || {
            let v = value.lock().unwrap();
            *v += 1; // <- Error
        });
    }

    std::thread::sleep(std::time::Duration::from_secs(1u64));

    println!("{:?}", dato);
}
  

不能将不可变局部变量v作为可变

借用

我知道更改为mut有效:

std::thread::spawn(move || {
    let mut v = value.lock().unwrap();
    *v += 1;
});

但为什么这样做:

let value = dato.clone();

std::thread::spawn(move || {
    *value.lock().unwrap() += 1;    
});

playground

1 个答案:

答案 0 :(得分:9)

value.lock().unwrap()返回类型为MutexGuard的值,其值为DerefMut

impl<'mutex, T: ?Sized> DerefMut for MutexGuard<'mutex, T> {
    fn deref_mut(&mut self) -> &mut T { ... }
}

DerefMut::deref_mut(x)相当于&mut *x;当然,DerefMut也用于指针下的赋值,就像你的情况一样。

因此,要使*v += 1生效,v应该是mut变量 - 否则根本不可能调用DerefMut::deref_mut

*value.lock().unwrap() += 1有效,因为现在value.lock().unwrap()是一个没有显式绑定的临时变量,因此Rust可以自动分配其可变性。

Mutex内部包含UnsafeCell的事实与DerefMut直接相关的这一事实无关;但是,它确实意味着Mutex提供了一种称为内部可变性的东西,即它允许通过共享引用来改变其内容。您可以在其上阅读更多内容in the book