gpt4 book ai didi

rust - 我如何安全地使用可变借用的对象?

转载 作者:行者123 更新时间:2023-11-29 08:36:15 24 4
gpt4 key购买 nike

我有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 blored as mutable 错误?

我猜这与 CellRefCell 有关,但我无法解决。

最佳答案

这是我将要使用的更简单的示例:

struct Manager<F> {
cb: F,
}
impl<F> Manager<F>
where F: FnMut()
{
fn do_a_bit_more_work(&mut self) { (self.cb)() }
}

struct Worker;
impl Worker {
fn do_work(&mut self) {}
fn get_progress(&self) -> u8 { 100 }
}

fn main() {
let mut worker = Worker;

let mut manager = Manager {
cb: || worker.do_work()
};

while worker.get_progress() < 100 {
manager.do_a_bit_more_work();
}
}

添加RefCell允许它编译:

use std::cell::RefCell;

fn main() {
let worker = RefCell::new(Worker);

let mut manager = Manager {
cb: || worker.borrow_mut().do_work()
};

while worker.borrow().get_progress() < 100 {
manager.do_a_bit_more_work();
}
}

现在闭包借用了 RefCell<Worker> 的不可变引用并检查排他性可变借用从编译时移动到运行时。

当然,RefCell不需要解决问题,但要避免 RefCell确实意味着你必须从不同的方向看问题。一种解决方案是不保留 Worker , 把它交给 Manager .然后根据需要借回来:

trait DoWork {
fn do_work(&mut self);
}

struct Manager<T> {
work: T,
}

impl<T> Manager<T>
where T: DoWork
{
fn do_a_bit_more_work(&mut self) {
self.work.do_work()
}

fn inspect<F, U>(&self, mut f: F) -> U
where F: FnMut(&T) -> U
{
f(&self.work)
}

// Optionally
// fn inspect_mut<F, U>(&mut self, mut f: F) -> U
// where F: FnMut(&mut T) -> U
// {
// f(&mut self.work)
// }

fn into_inner(self) -> T {
self.work
}
}

struct Worker;
impl Worker {
fn get_progress(&self) -> u8 {
100
}
}

impl DoWork for Worker {
fn do_work(&mut self) {}
}

fn main() {
let worker = Worker;

let mut manager = Manager { work: worker };

while manager.inspect(|w| w.get_progress()) < 100 {
manager.do_a_bit_more_work();
}

let worker = manager.into_inner();
}

关于rust - 我如何安全地使用可变借用的对象?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41266071/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com