rust - 迭代特征对象的可变引用向量

标签 rust borrow-checker

我有一个 struct 包含对 trait 对象的可变引用:

trait Task {
    fn do_it(&mut self);
}

struct Worker<'a> {
    tasks: Vec<&'a mut Task>,
}

Worker 的方法中,我想遍历任务并调用它们的 do_it:

impl<'a> Worker<'a> {
    pub fn work(&mut self) {
        for task in self.tasks.iter() {
            self.work_one(*task);
        }
    }

    fn work_one(&self, task: &mut Task) {
        task.do_it();
    }
}

可悲的是,借阅检查员不让我这样做:

error[E0389]: cannot borrow data mutably in a `&` reference
  --> src/main.rs:12:27
   |
12 |             self.work_one(*task);
   |                           ^^^^^ assignment into an immutable reference

我不能使 Worker 通用,因为我希望它能处理多种类型的任务。我还需要可变的任务。我如何在 Rust 中做到这一点?

最佳答案

您正在调用 tasks.iter(),它会生成对 Vec 元素的不可变引用。你实际上得到了 &&mut Task,一个对可变对象的不可变引用(这就是 Rust 编译器提示的原因)。

要解决此问题,请调用 tasks.iter_mut() 以获取可变引用的迭代器。

第二个问题是将 work_one 定义为调用方法。您在迭代时已经从 self 借用了一个可变引用,因此您无法再次借用。

工作示例(playground):

trait Task {
    fn do_it(&mut self);
}

struct Worker<'a> {
    tasks: Vec<&'a mut Task>,
}

impl<'a> Worker<'a> {
    pub fn work(&mut self) {
        for task in self.tasks.iter_mut() {
            Worker::work_one(*task);
        }
    }

    fn work_one(task: &mut Task) {
        task.do_it();
    }
}

要在 work_one 中仍然可以访问 self,可以使用此解决方法。这基本上只是交换了两个向量,因此您在迭代时实际上并没有借用 self 然后将其交换回来。这很难看,这里可能有更好的模式,也许其他人会提出更好的建议。

pub fn work(&mut self) {
    let mut tasks = vec![];
    mem::swap(&mut tasks, &mut self.tasks);
    for task in tasks.iter_mut() {
        self.work_one(*task);
    }
    mem::swap(&mut tasks, &mut self.tasks);
}

@Veedrac 建议的更好的替代方案:

fn work(&mut self) {
    let mut tasks = mem::replace(&mut self.tasks, Vec::new());
    for task in &mut tasks {
        self.work_one(*task);
    }
    self.tasks = tasks;
}

关于rust - 迭代特征对象的可变引用向量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36991399/

相关文章:

error-handling - 将错误消息返回到期望 'Box<dyn Error>' 的函数

rust - if-let 和一对短路吗?

rust - 结构方法: Cannot borrow as mutable because it is also borrowed as immutable

oop - 为什么 Rust 不支持特征对象向上转换?

generics - [T; 之间有什么区别? N] 和 U 如果 U 总是设置为 [T; N]?

web - 如何在 actix-web 中定义 URL 参数?

reference - Rust 中的生命周期注解会改变变量的生命周期吗?

rust - Rust 的借用检查器是否使这个切片示例过于复杂?

rust - 在存在借用的情况下,值(value)在闭包和组合器中过早下降

rust - 在Rust中存储包含闭包的结构的向量