rust - 如何将我的可变引用传递给 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
解决方案
我用来解决此类问题的一种方法是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) -> {
...
}
}
}
推荐阅读
- python - 从 Numpy 数组中选择每列满足某些条件的所有行
- javascript - 如何从 AWS Auth.currentSession() 返回的 Promise 中获取返回值
- r - 变量 R 的所有可能组合
- aws-organizations - awsorganization 尝试从仅修订版可用帐户创建 iam 用户失败
- laravel - 反映后,我想在表单页面中显示更改
- apache-spark - PySpark:从查找表中选择值进行计算
- javascript - 多行输出,多个变量使用innerHTML
- javascript - 无法读取未定义 ts-node esm 的属性“文本”
- latex - 在进行数组时,有没有办法在 Latex 中用插入数字的单词来标记方程式?
- javascript - 带有文件名 JavaScript 的多个图像上传预览