If I can guarantee that a value will exist in a HashMap for a specific key, such that either of the three options below will not panic, what would be the most idiomatic way of doing so?
let mut example_map: HashMap<String, String> = HashMap::new();
let key = String::from("Test_Key");
let value = String::from("Test Value");
example_map.insert(key.clone(), value);
let foo = example_map[&key].clone();
let bar = example_map.get(&key).unwrap().clone();
let baz = example_map.get(&key).expect("failure message").clone();
I would always use a safe access pattern. No matter how much you can guarantee now that the value will be there, you can't be certain this will hold on in the future.
if let Some(baz) = example_map.get(&key) {
// Do something with baz here
}
Sounds like a great reason to use a panicking version, so you find out when you're wrong. Stumbling along in the dark when your understanding of the code is wrong is much worse than a panic.
This is bad advice. If you detect that an invariant is violated, it's much preferable to panic than to silently ignore the issue. Therefore, example_map[&key] (which panics), or an explicit panic or expect with a more specific error message, is the right solution here.
Even when the invariant changes in the future, ignoring a missing key might well not be the correct way to handle it. So your code is not future-proof against such a change.
Since I control the creation of the map and when it is accessed/modified, any missing entries are completely invalid and not acceptable in the program logic.
Even if you control every aspect of the lifespan of the HashMap?
I can see that for data received from 3rd party crates, but a HashMap that is created, modified and accessed, with restrictions around keys being present while they are in use, and that the keys should be there based on program logic?
Ideally, I would love some data structure that guarantees the data is present, but that is close to impossible LOL.
Why would you choose this over the other two options?
I can see the cleaner design vs get().unwrap(), but isn't there value in adding a message to expect() if something seriously goes wrong?
Do you know if there is a performance or generated code difference between map[key] or map.get(key)? More just for curiosity sake, as I highly doubt there is a significant difference.
Well, the map[key] version actually tells LLVM that the panic is unlikely, so it'll optimize based on that. The if let Some(v) = map.get(key) version doesn't say which is unusual (unless you use PGO).
Does that matter? Probably not really.
But it's just another example where panicking can actually make things better. Kinda like how assert!(x.len() >= 3); can actually make stuff faster by eliding bounds checks later.
Fair point (same for @tczajka, this repply is both of your comments). If this is an invariant, panicking is the way to go, but if this logic lives within some code where execution of the program is expected to continue, then the advice should be to return an error so that it can be handled downstream.
if let Some(baz) = example_map.get(&key) {
// Do something with baz here
} else {
return Err(// Oopsie, we expected baz to be here)
}
If you need a specific message, use map.get(key).expect("message"). And that's the whole point: it only depends on your requirements.
Look at this thread: there is no single wrong answer here. All statements are perfectly valid. The disagreements have their origin in the different requirements everybody assumes.
So the question for the perfect solution (does that exist?) is not a question of the most idiomatic way, but of what is a good, solid solution for a specific problem, including all surrounding conditions.
You deal with that in the else clause. Do not panic because a value is missing
The original example
let mut example_map: HashMap<String, String> = HashMap::new();
let key = String::from("Test_Key");
let value = String::from("Test Value");
example_map.insert(key.clone(), value);
let foo = example_map[&key].clone();
yes panic, the value is there. But it is an artificial example.
In reality, do not panic in the normal course of events, and a key missing is normal. Panic when you no longer have a way out....