Rust 在调用HashMap::get时,我是否可以使用任何构造来允许对HashMap进行变异?
我正试图在Rust中实现Dijkstra的算法。我得到一个错误,因为我在Rust 在调用HashMap::get时,我是否可以使用任何构造来允许对HashMap进行变异?,rust,Rust,我正试图在Rust中实现Dijkstra的算法。我得到一个错误,因为我在匹配表达式中对从.get()获得的值进行HashMap变异。我理解为什么这违反了Rust的借用和变异原则,但我还没有找到解决办法 我已尝试使用.entry()和和_modify()执行就地修改,但我还需要插入和/或修改匹配的键之外的其他键 我是否可以使用任何构造/函数在get中安全地启用此变异,或者,如果失败,是否有其他方法可以避免此问题 (未完成)代码段: use std::collections::{HashMap, H
匹配
表达式中对从.get()
获得的值进行HashMap
变异。我理解为什么这违反了Rust的借用和变异原则,但我还没有找到解决办法
我已尝试使用.entry()
和和_modify()
执行就地修改,但我还需要插入和/或修改匹配的键之外的其他键
我是否可以使用任何构造/函数在get
中安全地启用此变异,或者,如果失败,是否有其他方法可以避免此问题
(未完成)代码段:
use std::collections::{HashMap, HashSet};
struct Graph {
vertices: Vec<i32>,
edges: HashMap<i32, HashMap<i32, i32>>, // start -> {end -> weight}
}
fn dijkstra(start: i32, g: Graph) -> HashMap<i32, HashMap<i32, (i32, Vec<i32>)>> {
let mut known_paths: HashMap<i32, (i32, Vec<i32>)> = HashMap::new(); // end -> (total_weight, path)
known_paths.insert(start, (0, Vec::new()));
let mut current = &start;
let mut unvisited: HashSet<i32> = g.edges.keys().cloned().collect();
while unvisited.len() > 0 {
match known_paths.get(current) {
Some((current_dist, current_path)) => if let Some(ref incident_edges) =
g.edges.get(current)
{
for (neighbor, dist) in incident_edges.iter() {
match known_paths.get(&neighbor) {
Some((old_distance, _old_path)) => if current_dist + dist < *old_distance {
let mut new_path = current_path.clone();
new_path.push(*current);
known_paths.insert(*neighbor, (current_dist + dist, new_path));
},
None => {
let mut new_path = current_path.clone();
new_path.push(*current);
known_paths.insert(*neighbor, (current_dist + dist, new_path));
}
}
}
},
None => panic!("Something went wrong with current={}", current),
}
}
HashMap::new()
}
否。
我收到一个错误,因为我正在对从.get()
获得的值在匹配表达式中变异哈希映射。我理解为什么这违反了Rust的借用和变异原则,但我还没有找到解决办法
恐怕你还没有真正理解借用原则
Rust安全性的关键原则是:变异和混叠
然后在运行时或编译时强制执行此原则,在可行时优先考虑编译时,因为它没有运行时开销
在您的情况下,您有:
HashMap
中的引用,从HashMap::get()
获取
您试图在按住引用的同时修改所述的哈希映射
让我们先想象一下,一些构造允许编译和运行这些代码;会发生什么动臂
在HashMap
中插入元素时,HashMap
可能:
洗牌现有元素,因为它使用罗宾汉散列
将所有元素转移到另一个(更大的)堆分配数组
因此,HashMap::insert
意味着对HashMap
元素的任何现有引用都可能变成悬空,并指向另一个元素或随机内存
在保存对HashMap
元素的引用时,没有安全的方法插入到HashMap
中
您需要找到一种解决方案,它不需要保留对HashMap
的引用
我的建议是简单地克隆
:匹配已知路径。get(current.clone()
。一旦您有了该算法的第一个工作实现,您可以根据需要考虑是否可能改进其性能。您的问题是什么?另请参见;等等@Shepmaster原谅我,考虑到错误和我对所需算法的陈述,我认为问题是隐含的。编辑。谢谢你提出的其他问题,这些问题都没有出现在我的谷歌搜索中。我会仔细看一下,看看能从中得到什么。@Shepmaster在阅读了上述答案后,我发现RefCell
可能会有所帮助,但我有一些问题。1) RefCell
似乎允许对映射中的一个值进行多个可变引用,但这是否有助于我在借用中改变多个键值对?2) 出于哲学上的原因,RefCell
似乎应该避免(或至少最小化),因为它避开了Rust的编译时借用检查。如果是这样的话,那么有没有一个很好的替代方法来解决上述算法,从而完全摆脱这个问题呢?非常好,信息丰富的答案。我从来没有想过要从我下面把HashMap
删除或克隆出来,这一点现在我想起来就很明显了。你提出的克隆get结果的建议听起来直截了当且可信,让我来处理一下,然后再给你回复。谢谢@Stargateur谢谢,也许在我完成自己的实现后,我会看看其他人的实现进行比较。我将此部分用作Rust的学习经验,因此,在不费力完成自己的实现的情况下查看另一个实现,这一点很难理解。