I'm trying to implement Dijkstra's algorithm in Rust. I am getting an error because I'm mutating a HashMap
inside a match
expression on a value obtained from .get()
. I understand why this is a violation of the borrowing and mutation principles of Rust, but I haven't found a workaround.
I have tried using .entry()
and .and_modify()
to perform an in-place modification, but I also need to insert and/or modify other keys besides the one being matched on.
Are there any constructs/functions I can use to safely enable this mutation within a get
, or, failing that, is there another approach to this algorithm that steers clear of this issue?
(Unfinished) Code Snippet:
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()
}
Error:
error[E0502]: cannot borrow `known_paths` as mutable because it is also borrowed as immutable
--> src/lib.rs:26:29
|
17 | match known_paths.get(current) {
| ----------- immutable borrow occurs here
...
26 | known_paths.insert(*neighbor, (current_dist + dist, new_path));
| ^^^^^^^^^^^ mutable borrow occurs here
...
37 | }
| - immutable borrow ends here
error[E0502]: cannot borrow `known_paths` as mutable because it is also borrowed as immutable
--> src/lib.rs:31:29
|
17 | match known_paths.get(current) {
| ----------- immutable borrow occurs here
...
31 | known_paths.insert(*neighbor, (current_dist + dist, new_path));
| ^^^^^^^^^^^ mutable borrow occurs here
...
37 | }
| - immutable borrow ends here