我正在尝试今年Rust中的Code出现,作为学习语言的一种方式。我已将输入(从第7天开始)解析为以下结构:
struct Process {
name: String,
weight: u32,
children: Vec<String>,
parent: Option<String>
}
这些存储在HashMap<String, Process>
中。现在我想迭代地图中的值并根据我在父级“子”向量中找到的内容更新父值。
什么行不通是
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中实现这一目标的最惯用方法是什么?我能看到的两个选项是:
有第三种选择吗?
答案 0 :(得分:4)
是的,您可以使用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
,那么 borrow
会在运行时发生恐慌。如果一个进程是它自己的父进程(这可能永远不会发生,但在一个更强大的程序中,你想要提供一个有意义的错误信息,而不仅仅是恐慌),就会发生这种情况。
我发明了一些名称并进行了一些小改动(除了专门指出的那些)以使这段代码编译。值得注意的是,p.name.clone()
制作了p.name
的完整副本。这是必要的,因为name
和parent
都归String
所有。