以下代码,其中结构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,因此无法编译。
我的问题是:
为什么通过Mutex
这样的智能指针使用原始结构时,结构却是特殊的?
如何直接在Mutex
上使用Arc
的功能?
我认为两者都与Deref
有关,但不确定如何。
答案 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}>`
另请参阅: