举个例子:

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);
}



我知道更改为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

最佳答案

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()是一个没有显式绑定(bind)的临时变量,因此Rust可以自由地自动分配其可变性。
Mutex的内部包含UnsafeCell的事实与DerefMut的特定问题无关。但是,这确实意味着Mutex提供了一种称为内部可变性的功能,即,它允许一个人通过一个共享引用来对其内容进行更改。您可以在in the book上阅读更多内容。

关于rust - 为什么Arc和Mutex允许我更改不可变变量的值?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/36773923/

10-11 21:49