Background
The HashSet and HashMap collections are standard structures from std::collections that implement fast hash-based lookup. They have been built into Rust since the early versions of the language, but the internal details of their usage often cause difficulties even for experienced developers due to the ownership system.
Issue
Confusion arises when inserting and retrieving elements (especially if values are not Copy), when altering the collection (mutable borrows), and also when using references as keys. There is also the problem of implementing proper Eq/Hash for user-defined types.
Solution
Code example:
use std::collections::HashMap; fn main() { let mut map = HashMap::new(); map.insert("key", 42); if let Some(value) = map.get("key") { println!("Found value: {}", value); } }
Key features:
Can you obtain multiple mutable references to the same HashMap element?
No, the borrow checker will not allow this to avoid ownership violations.
Can you use the string literal "abc" directly as a key in HashMap<String, V>?
No, it expects exactly String, while "abc" is &'static str. A conversion is required: insert("abc".to_string(), val).
Can you extract a value from HashMap, keeping it in a separate variable, and continue to use HashMap?
Yes, you can take a reference to the value via get — but if you do remove (or extract by move), then HashMap mutates, and any old references become invalid.
Attempting to borrow both the key and value at the same time, and then mutating the collection:
let mut map = HashMap::new(); map.insert("abc".to_string(), 10); let val = map.get("abc"); map.insert("def".to_string(), 20); // borrow checker error
Pros:
Cons:
Extracting a value, working only with its copy or clone:
let mut map = HashMap::new(); map.insert("abc".to_string(), 10); if let Some(val) = map.get("abc") { let val = *val; // copy map.insert("def".to_string(), 20); // all works }
Pros:
Cons: