我怎样才能同时迭代 Rust HashMap 并修改它的一些值?
How can I simultaneously iterate over a Rust HashMap and modify some of its values?
今年我正在尝试使用 Rust 中的 Advent of Code 作为学习这门语言的一种方式。我已将输入(从第 7 天开始)解析为以下结构:
struct Process {
name: String,
weight: u32,
children: Vec<String>,
parent: Option<String>
}
这些存储在 HashMap<String, Process>
中。现在我想根据我在父级 "children" 向量中找到的值迭代地图中的值并更新父级值。
没用的是
for p in self.processes.values() {
for child_name in p.children {
let mut child = self.processes.get_mut(child_name).expect("Child not found.");
child.parent = p.name;
}
}
我不能同时拥有对 HashMap
(self.processes
) 的可变引用和非可变引用,或两个可变引用。
那么,在 Rust 中实现这一点最惯用的方法是什么?我可以看到的两个选项是:
- 一次性将 parent/child 关系复制到新的临时数据结构中,然后在不可变引用超出范围后,在第二遍中更新 Process 结构。
- 更改我的数据结构以将 "parent" 放入其自己的 HashMap 中。
还有第三种选择吗?
是的,您可以使用 RefCell
:
为 HashMap
的值授予内部可变性
struct ProcessTree {
processes: HashMap<String, RefCell<Process>>, // change #1
}
impl ProcessTree {
fn update_parents(&self) {
for p in self.processes.values() {
let p = p.borrow(); // change #2
for child_name in &p.children {
let mut child = self.processes
.get(child_name) // change #3
.expect("Child not found.")
.borrow_mut(); // change #4
child.parent = Some(p.name.clone());
}
}
}
}
borrow_mut
如果 child 已经被 borrow
借用,将在运行时出现 panic。如果一个进程是它自己的父进程,就会发生这种情况(这应该永远不会发生,但在一个更健壮的程序中,你会想要给出一个有意义的错误消息,而不仅仅是恐慌)。
我发明了一些名称并做了一些小改动(除了特别指出的那些)以使这段代码可以编译。值得注意的是,p.name.clone()
制作了 p.name
的完整副本。这是必要的,因为 name
和 parent
都拥有 String
。
今年我正在尝试使用 Rust 中的 Advent of Code 作为学习这门语言的一种方式。我已将输入(从第 7 天开始)解析为以下结构:
struct Process {
name: String,
weight: u32,
children: Vec<String>,
parent: Option<String>
}
这些存储在 HashMap<String, Process>
中。现在我想根据我在父级 "children" 向量中找到的值迭代地图中的值并更新父级值。
没用的是
for p in self.processes.values() {
for child_name in p.children {
let mut child = self.processes.get_mut(child_name).expect("Child not found.");
child.parent = p.name;
}
}
我不能同时拥有对 HashMap
(self.processes
) 的可变引用和非可变引用,或两个可变引用。
那么,在 Rust 中实现这一点最惯用的方法是什么?我可以看到的两个选项是:
- 一次性将 parent/child 关系复制到新的临时数据结构中,然后在不可变引用超出范围后,在第二遍中更新 Process 结构。
- 更改我的数据结构以将 "parent" 放入其自己的 HashMap 中。
还有第三种选择吗?
是的,您可以使用 RefCell
:
HashMap
的值授予内部可变性
struct ProcessTree {
processes: HashMap<String, RefCell<Process>>, // change #1
}
impl ProcessTree {
fn update_parents(&self) {
for p in self.processes.values() {
let p = p.borrow(); // change #2
for child_name in &p.children {
let mut child = self.processes
.get(child_name) // change #3
.expect("Child not found.")
.borrow_mut(); // change #4
child.parent = Some(p.name.clone());
}
}
}
}
borrow_mut
如果 child 已经被 borrow
借用,将在运行时出现 panic。如果一个进程是它自己的父进程,就会发生这种情况(这应该永远不会发生,但在一个更健壮的程序中,你会想要给出一个有意义的错误消息,而不仅仅是恐慌)。
我发明了一些名称并做了一些小改动(除了特别指出的那些)以使这段代码可以编译。值得注意的是,p.name.clone()
制作了 p.name
的完整副本。这是必要的,因为 name
和 parent
都拥有 String
。