【发布时间】:2016-12-21 15:16:03
【问题描述】:
我有this code:
use std::sync::atomic::{AtomicIsize, Ordering};
#[derive(Default)]
pub struct Worker {
work: Vec<u32>,
progress: AtomicIsize,
}
impl Worker {
fn do_work(&mut self) {
self.work.push(0u32);
self.progress.store(self.progress.load(Ordering::SeqCst) + 1, Ordering::SeqCst);
}
fn get_progress(&self) -> isize {
self.progress.load(Ordering::SeqCst)
}
}
pub struct Manager<CB: FnMut()> {
cb: CB
}
impl<CB: FnMut()> Manager<CB> {
fn do_a_bit_more_work(&mut self) {
(self.cb)();
}
}
fn main() {
let mut worker = Worker::default();
let mut manager = Manager {
cb: || worker.do_work()
};
while worker.get_progress() < 100 {
manager.do_a_bit_more_work();
}
}
也就是说,我有一些经理会调用回调来做一些工作。我希望回调为Worker::do_work(),并且该函数会更新Worker 的成员,因此它需要&mut self。但是,一旦我将worker.do_work() 传递给经理,这意味着worker 是可变借用的,所以我再也不能使用它了。
我想再次使用它来检查进度,并可能改变它的行为。我可以使用原子操作和互斥锁等来尝试确保这样做是安全的,但是我如何告诉 Rust 允许这样做而不会出现 cannot borrow X as immutable because it is also borrowed as mutable 错误?
我猜这与 Cell 或 RefCell 有关,但我无法解决。
【问题讨论】:
-
请展示您使用
Cell和RefCell完成的工作。 std::cell 文档中有很多关于这些类型的文档。 -
对您提出的问题的直接回答(我如何告诉 Rust 可以在已经可变借用时将 self 作为不可变借用?)是:you不要。这样做本质上是不安全的。
-
@ker:我知道
Cell和RefCell的想法,我只是不确定如何最好地将它们应用于这种情况。文档对此并没有真正的帮助。 -
一个(非)可编译的最小示例,我相信它证明了 OP 得到的确切错误:playground。尽管 OP 的代码存在明显的缺点,但我也很好奇如何构造事物以使
while循环成为可能。 -
如果示例代码避免在其他可变数据结构中无偿使用原子类型,那么它的混淆就会减少。请注意,
x.store(x.load() + 1)是一种反模式,它违背了 any 语言中原子的目的。
标签: rust immutability borrow-checker