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

时间:2016-05-02 20:47:28

标签: rust borrow-checker

我有一个struct,它包含对特征对象的可变引用:

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中做到这一点?

2 个答案:

答案 0 :(得分:14)

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

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

第二个问题是将work_one定义为一种方法。

工作示例(playground):

self

要仍然可以访问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(); } } self中的work_one,可以使用此解决方法。这基本上只是交换两个向量,因此您在迭代时不会实际借用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;
}

答案 1 :(得分:3)

您需要对每个项目进行可变引用。 iter返回不可变引用。对可变变量的不可变引用本身并不可变。请改用iter_mutfor task in &mut self.tasks

然后,最简单的要做的就是将work_one内联到work

pub fn work(&mut self) {
    for task in self.tasks.iter_mut() {
        task.do_it()
    }
}

不幸的是,将它分成两个函数非常痛苦。您必须保证调用self.work_one不会修改self.tasks。 Rust不会跨函数边界跟踪这些事情,因此您需要拆分所有其他成员变量并将它们分别传递给函数。

另见: