闭包需要对“self”进行唯一访问,但它已经被借用了

que*_*dam 2 rust

我基本上有以下代码需要修改向量场(通过函数删除一些项目retains),并且在该函数的谓词中retains,我需要在 self 上调用一个可变函数:

struct Task {}

struct Processor {
    counter: u32,
    tasks: Vec<Task>
}

impl Processor {
    
    fn execute(&mut self, task: &Task) -> bool {
        self.counter += 1;
        // Do some stuff with task and return wether it was sucessfully executed
        true
    }

    fn run(&mut self) {
        self.tasks.retain(|task| !self.execute(task))
    }
}
Run Code Online (Sandbox Code Playgroud)

编译器抱怨两个错误:

error[E0501]: cannot borrow `self.tasks` as mutable because previous closure requires unique access
  --> src/main.rs:90:9
   |
90 |         self.tasks.retain(|task| !self.execute(task))
   |         ^^^^^^^^^^^------^------^^----^^^^^^^^^^^^^^^
   |         |          |      |       |
   |         |          |      |       first borrow occurs due to use of `self` in closure
   |         |          |      closure construction occurs here
   |         |          first borrow later used by call
   |         second borrow occurs here

error[E0500]: closure requires unique access to `self` but it is already borrowed
  --> src/main.rs:90:27
   |
90 |         self.tasks.retain(|task| !self.execute(task))
   |         ---------- ------ ^^^^^^  ---- second borrow occurs due to use of `self` in closure
   |         |          |      |
   |         |          |      closure construction occurs here
   |         |          first borrow later used by call
   |         borrow occurs here
Run Code Online (Sandbox Code Playgroud)

我确实理解这个问题,但我该如何使其发挥作用?

Pit*_*taJ 5

Rust 还没有办法只借用self. 因此,它不能推断您没有self.tasks同时发生突变self.counter。它只知道你试图self同时突变两次。

要解决此问题,您需要移出tasksself然后执行所需的操作,然后将其移回self

Rust 有一个方便的操作,可以在标准库中完成此操作。由于Vec实现了Default(产生一个空向量,不需要分配),我们可以使用std::mem::take

    fn run(&mut self) {
        // swaps `self.tasks` with an empty `Vec`, and yields `tasks` to us
        // this won't allocate, because `Vec::new` and therefore `Vec::default` do not
        let mut tasks = std::mem::take(&mut self.tasks);
        // do what we want with it
        tasks.retain(|task| !self.execute(task));
        // move it back into `self`
        self.tasks = tasks;
    }
Run Code Online (Sandbox Code Playgroud)

操场