I've turned everything into String and it's still complaining. No clue why.
let mut nodes: HashMap<&String, NodeIndex> = HashMap::new();
let mut graph = Graph::<String, u32>::new();
for line in input.split('\n') {
println!("Record: {}", line);
let (container, colors) = parse_line(line);
let node = match nodes.get(&container) {
Some(n) => *n,
None => {
let ni = graph.add_node(container);
nodes.insert(&container, ni);
ni
}
};
for col in colors {
let contained_node = match nodes.get(&container) {
Some(n) => *n,
None => {
let ni = graph.add_node(col);
nodes.insert(&container, ni);
ni
}
};
graph.add_edge(node, contained_node, 0);
}
}
println!("Generated graph: {:?}", graph);
Code with all changes necessary to get to the borrowck error:
use petgraph::prelude::*;
use std::collections::HashMap;
fn make_graph(input: &str) {
let mut nodes: HashMap<&String, NodeIndex> = HashMap::new();
let mut graph = Graph::<String, u32>::new();
for line in input.split('\n') {
println!("Record: {}", line);
let (container, colors) = parse_line(line);
let node = match nodes.get(&container) {
Some(n) => *n,
None => {
let ni = graph.add_node(container);
nodes.insert(&container, ni);
ni
}
};
for col in colors {
let contained_node = match nodes.get(&container) {
Some(n) => *n,
None => {
let ni = graph.add_node(col);
nodes.insert(&container, ni);
ni
}
};
graph.add_edge(node, contained_node, 0);
}
}
println!("Generated graph: {:?}", graph);
}
fn parse_line(line: &str) -> (String, Vec<String>) {todo!();}
The borrowck errors:
error[E0597]: `container` does not live long enough
--> src/lib.rs:17:30
|
13 | let node = match nodes.get(&container) {
| ----- borrow later used here
...
17 | nodes.insert(&container, ni);
| ^^^^^^^^^^ borrowed value does not live long enough
...
34 | }
| - `container` dropped here while still borrowed
error[E0382]: borrow of moved value: `container`
--> src/lib.rs:17:30
|
11 | let (container, colors) = parse_line(line);
| --------- move occurs because `container` has type `String`, which does not implement the `Copy` trait
...
16 | let ni = graph.add_node(container);
| --------- value moved here
17 | nodes.insert(&container, ni);
| ^^^^^^^^^^ value borrowed here after move
error: aborting due to 2 previous errors; 1 warning emitted
The second error says that you first moved container into graph and then tried to take a reference to the old location and store it in nodes. This won't work. The first error says that you tried to store a reference to the container value, which only lives inside the first for loop and try to store it in a value that outlives the first for loop.
You are trying to borrow a variable after giving the ownership to another function. You can't use a variable after you move it. Try reading the part about ownership in the book.
I'm going to reread the chapter in the O'Reilly book and then read this one too but they weren't too clear to begin with.
I fixed it by not trying to put the same string in the Graph (which seems to be useless anyway) and moving ownership to the HashMap:
let mut nodes: HashMap<String, NodeIndex> = HashMap::new();
let mut graph = Graph::<u32, u32>::new();
for line in input.split('\n') {
println!("Record: {}", line);
let (container, colors) = parse_line(line);
let node = match nodes.get(container.as_str()) {
Some(n) => *n,
None => {
let ni = graph.add_node(0);
nodes.insert(container, ni);
ni
}
};
for col in colors {
let contained_node = match nodes.get(col.as_str()) {
Some(n) => *n,
None => {
let ni = graph.add_node(0);
nodes.insert(col, ni);
ni
}
};
graph.add_edge(node, contained_node, 0);
}
}
println!("Generated graph: {:?}", graph);
I might just be over-explaining things, but as bjorn3 says:
Your initial HashMap had a reference &String in it
You would then later insert a reference to &container:
But for the reference to remain valid the original version of it must be owned somewhere. The variable container is created and goes out of scope in each loop. Your switch to .as_str() is solving that by using a function which returns a new owned value.
It sounds like you might want the string to be owned by just one of the objects you're inserting it into. I'd think about reordering your code to insert the owned version first, and then make the reference to that owned version in the nodes HashMaps instead of to &container.