首页 > 解决方案 > 如何将我的可变引用传递给 Rust 中的迭代器循环内的函数?

问题描述

我有以下代码:

    pub fn run_systems(mut self) {
        for mut agent in self.agents.iter_mut() {
            for mut system_id in agent.systems.iter_mut() {
                let system = self.systems.get(system_id).unwrap();
                system.simulate(&mut agent,  &mut self);
            }
        }
    }

我收到以下错误system.simulate

cannot borrow `agent` as mutable more than once at a time
second mutable borrow occurs here`. Apparently, iterating over the arrays is a borrowing operation.

我也尝试过不使用该iter函数并直接在拥有的值上进行迭代(不确定它的作用):

    pub fn run_systems(mut self) {
        for mut agent in self.agents {
            for mut system_id in agent.systems {
                let system = self.systems.get(&system_id).unwrap();
                system.simulate(&mut agent,  &mut self);
            }
        }
    }

但是一旦我引用它,它就会检测到行&system_id中的隐式借用for mut system_id in agent.systems {

borrow of partially moved value: `agent`
partial move occurs because `agent.systems` has type `Vec<String>`, which does not implement the `Copy` traitrustcE0382
lib.rs(72, 34): `agent.systems` partially moved due to this implicit call to `.into_iter()`
collect.rs(233, 18): this function takes ownership of the receiver `self`, which moves `agent.systems`

我尝试了各种方法来编写这段代码,但找不到可行的方法。如何迭代这些值,同时还能将对其内容的可变引用传递给其他函数?

这是它的游乐场

use std::collections::HashMap;

struct World {
    agents: Vec<Agent>,
    systems: HashMap<String, Box<dyn System>>,
}
impl World {
    pub fn new() -> World {
        return World {
            agents: Vec::new(),
            systems: HashMap::new(),
        };
    }
    pub fn run_systems(mut self) {
        for mut agent in self.agents {
            for system_id in agent.systems {
                let system = self.systems.get(&system_id).unwrap();
                system.simulate(&mut agent, &mut self);
            }
        }
    }
    /// Adds an agent to the world
    pub fn add_agent(&mut self, agent: Agent) -> &Self {
        self.agents.push(agent);
        return self;
    }

    /// Adds a system to the available systems
    pub fn add_system<S: System + 'static>(&mut self, system: S, id: String) -> &Self {
        self.systems.insert(id, Box::new(system));
        return self;
    }
}

struct Agent {
    systems: Vec<String>,
}

trait System {
    fn simulate(&self, agent: &mut Agent, world: &mut World);
}

#[derive(Default)]
struct SomeSystem;
impl System for SomeSystem {
    fn simulate(&self, agent: &mut Agent, world: &mut World) {
        // Code here
    }
}

fn main() {
    let system_id = String::from("SOME_SYSTEM");
    let world = World::new();
    world.add_system(SomeSystem::default(), system_id);
    let agent = Agent {
        systems: vec![system_id],
    };
    world.add_agent(agent);
    world.run_systems();
}
error[E0382]: borrow of partially moved value: `agent`
   --> src/main.rs:18:33
    |
16  |             for system_id in agent.systems {
    |                              -------------
    |                              |
    |                              `agent.systems` partially moved due to this implicit call to `.into_iter()`
    |                              help: consider borrowing to avoid moving into the for loop: `&agent.systems`
17  |                 let system = self.systems.get(&system_id).unwrap();
18  |                 system.simulate(&mut agent, &mut self);
    |                                 ^^^^^^^^^^ value borrowed here after partial move
    |
note: this function takes ownership of the receiver `self`, which moves `agent.systems`
    = note: partial move occurs because `agent.systems` has type `Vec<String>`, which does not implement the `Copy` trait

error[E0502]: cannot borrow `self` as mutable because it is also borrowed as immutable
  --> src/main.rs:18:45
   |
17 |                 let system = self.systems.get(&system_id).unwrap();
   |                              ------------ immutable borrow occurs here
18 |                 system.simulate(&mut agent, &mut self);
   |                        --------             ^^^^^^^^^ mutable borrow occurs here
   |                        |
   |                        immutable borrow later used by call

error[E0382]: borrow of partially moved value: `self`
  --> src/main.rs:18:45
   |
15 |         for mut agent in self.agents {
   |                          -----------
   |                          |
   |                          `self.agents` partially moved due to this implicit call to `.into_iter()`
   |                          help: consider borrowing to avoid moving into the for loop: `&self.agents`
...
18 |                 system.simulate(&mut agent, &mut self);
   |                                             ^^^^^^^^^ value borrowed here after partial move
   |
   = note: partial move occurs because `self.agents` has type `Vec<Agent>`, which does not implement the `Copy` trait

error[E0596]: cannot borrow `world` as mutable, as it is not declared as mutable
  --> src/main.rs:54:5
   |
53 |     let world = World::new();
   |         ----- help: consider changing this to be mutable: `mut world`
54 |     world.add_system(SomeSystem::default(), system_id);
   |     ^^^^^ cannot borrow as mutable

error[E0382]: use of moved value: `system_id`
  --> src/main.rs:56:23
   |
52 |     let system_id = String::from("SOME_SYSTEM");
   |         --------- move occurs because `system_id` has type `String`, which does not implement the `Copy` trait
53 |     let world = World::new();
54 |     world.add_system(SomeSystem::default(), system_id);
   |                                             --------- value moved here
55 |     let agent = Agent {
56 |         systems: vec![system_id],
   |                       ^^^^^^^^^ value used here after move

error[E0596]: cannot borrow `world` as mutable, as it is not declared as mutable
  --> src/main.rs:58:5
   |
53 |     let world = World::new();
   |         ----- help: consider changing this to be mutable: `mut world`
...
58 |     world.add_agent(agent);
   |     ^^^^^ cannot borrow as mutable

标签: rust

解决方案


我用来解决此类问题的一种方法是simulate不接受可变引用,而是返回它希望执行的操作列表。这可能看起来像这样:


// No longer uses mutable references, and returns a list of 
// actions to perform on the world.
trait System {
    fn simulate(&self, agent: &Agent, world: &World) -> Vec<Action>;
}

enum Action {
   ...
}

impl World {
    ...

    pub fn run_systems(&mut self) {
        let mut actions = vec![];
        for agent in &self.agents {
            for system_id in &agent.systems {
                let system = self.systems.get(system_id).unwrap();
                actions.extend(system.simulate(agent, self));
            }
        }

        for action in actions {
            self.apply_action(action)
        }
    }

    pub fn apply_action(&mut self, action: &Action) {
        match(action) {
           case SomeAction(agent_id) -> {
             ...
        }
    }
}

推荐阅读