互斥体可以引用结构的,但不能引用基元

时间:2019-08-10 15:10:52

标签: rust

以下代码,其中结构Counter包装u32。我正在使用Arc进行包装,并使用Mutex进行安全且共享的值访问。我已经省略了线程代码以提供一个简单的示例:

use std::sync::{Arc, Mutex};

fn main() {
    #[derive(Debug)]
    struct Counter {
        count: u32,
    }

    let counter = Arc::new(Mutex::new(Counter { count: 0 }));

    for _ in 0..10 {
        let mut c_int = counter.lock().unwrap();
        c_int.count += 1;
    }

    println!("{:?}", counter.lock().unwrap());
}

这里counter.lock().unwrap()可以透明地锁定互斥锁并解包结果,而我不需要取消引用Arc。取消对c_int的引用也可以透明地进行。

考虑以下代码,其中Counter替换为u32

use std::sync::{Arc, Mutex};

fn main() {
    let counter = Arc::new(Mutex::new(32));

    for _ in 0..10 {
        let mut c_int = counter.lock().unwrap();
        c_int += 1;
    }

    println!("{:?}", counter.lock().unwrap());
}

由于c_int += 1无效,因为它没有取消引用u32,因此无法编译。

我的问题是:

  1. 为什么通过Mutex这样的智能指针使用原始结构时,结构却是特殊的?

  2. 如何直接在Mutex上使用Arc的功能?

我认为两者都与Deref有关,但不确定如何。

1 个答案:

答案 0 :(得分:4)

c_int实际上不是整数或Counter实例,它是std::sync::MutexGuard<'_, T>

c_int.count += 1;在第一个示例中起作用的原因是Deref强制:无论在哪里看到诸如foo.bar之类的表达式,编译器都会检查foo是否具有成员{ {1}},如果没有,则取消引用它,然后重试。在您的情况下,由于bar是互斥保护,因此它没有c_int成员,因此编译器将尝试count

现在,(*c_int).count确实实现了std::sync::MutexGuard<'_, T>,在您的情况下,这意味着您可以从互斥保护中获取Deref<Target=T>,然后编译器就在那里停止了。

但是,在整数情况下,您只有Counter,赋值本身不会触发c_int += 1强制,因此编译器正确地给您一个错误

Deref

要使第二个示例生效,您必须取消引用自己:

8 |         (c_int) += 1;
  |         -------^^^^^
  |         |
  |         cannot use `+=` on type `std::sync::MutexGuard<'_, {integer}>`

另请参阅: