Rust 在调用HashMap::get时,我是否可以使用任何构造来允许对HashMap进行变异?

Rust 在调用HashMap::get时,我是否可以使用任何构造来允许对HashMap进行变异?,rust,Rust,我正试图在Rust中实现Dijkstra的算法。我得到一个错误,因为我在匹配表达式中对从.get()获得的值进行HashMap变异。我理解为什么这违反了Rust的借用和变异原则,但我还没有找到解决办法 我已尝试使用.entry()和和_modify()执行就地修改,但我还需要插入和/或修改匹配的键之外的其他键 我是否可以使用任何构造/函数在get中安全地启用此变异,或者,如果失败,是否有其他方法可以避免此问题 (未完成)代码段: use std::collections::{HashMap, H

我正试图在Rust中实现Dijkstra的算法。我得到一个错误,因为我在
匹配
表达式中对从
.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的学习经验,因此,在不费力完成自己的实现的情况下查看另一个实现,这一点很难理解。