Introduction
std::collections::HashMap<K, V> stores data as key-value pairs, allowing you to look up a value quickly using its associated key rather than a numeric index. It's ideal for problems like counting word frequencies, caching computed results, or associating IDs with records. Keys must implement the Eq and Hash traits so the map can compare and hash them internally.
Cricket analogy: HashMap<K, V> is like a scorer's lookup table keyed by player name to instantly retrieve a batting average instead of scanning the whole scorecard; player names must be hashable and comparable to serve as keys.
Syntax
use std::collections::HashMap;
let mut scores: HashMap<String, i32> = HashMap::new();
scores.insert(String::from("Alice"), 90);
scores.insert(String::from("Bob"), 85);
let alice_score = scores.get("Alice");Explanation
HashMap::new() creates an empty map, and .insert(key, value) adds or overwrites an entry for that key. .get(&key) returns Option<&V> — Some(&value) if the key exists, or None if it doesn't — so lookups never panic. A very common idiom is .entry(key).or_insert(default), which inserts a default value only if the key is absent and then returns a mutable reference to the value, perfect for upsert-style counters. Because a HashMap is backed by hashing rather than ordering, iterating over its entries does not follow insertion order and can vary between runs.
Cricket analogy: HashMap::new() starts an empty run-tally, .insert(player, runs) adds or overwrites a score; .get(&player) returns Option<&i32> so a missing player never panics; .entry(player).or_insert(0) is perfect for tallying runs as each ball is bowled, though the tally won't print in batting order.
Example
use std::collections::HashMap;
fn main() {
let text = "the quick brown fox the lazy dog the";
let mut counts: HashMap<&str, i32> = HashMap::new();
for word in text.split_whitespace() {
let count = counts.entry(word).or_insert(0);
*count += 1;
}
println!("the: {}", counts.get("the").unwrap());
println!("fox: {}", counts.get("fox").unwrap());
println!("missing: {:?}", counts.get("cat"));
}
// Output:
// the: 3
// fox: 1
// missing: NoneKey Takeaways
- HashMap<K, V> stores key-value pairs for fast average-case lookup by key.
- Keys must implement the Eq and Hash traits.
.insert()adds or overwrites;.get()returns Option<&V> for safe lookups..entry(key).or_insert(default)is the idiomatic pattern for upsert/counter logic.- Iteration order over a HashMap is unspecified and not guaranteed to match insertion order.
Practice what you learned
1. What must a type implement to be used as a HashMap key?
2. What does `.get(&key)` return on a HashMap?
3. What is the idiomatic way to increment a counter for a word using a HashMap?
4. What happens to iteration order when you loop over a HashMap's entries?
5. What does calling `.insert()` with a key that already exists do?
Was this page helpful?
You May Also Like
Vectors in Rust
A Vec<T> is a growable, heap-allocated list that lets you store a variable number of values of the same type.
The Option Type in Rust
Understand how Rust's Option<T> enum replaces null to represent optional values safely.
Structs in Rust
Structs let you group related values into a single named type with fields you access by name.
Closures in Rust
Understand Rust closures, their capture modes, and the Fn, FnMut, and FnOnce traits that govern how they use captured variables.
Related Reading
Related Study Notes in Programming
Browse all study notesApache Spark Study Notes
Programming · 30 topics
ProgrammingApache Flink Study Notes
Programming · 30 topics
ProgrammingHadoop Study Notes
Programming · 30 topics
ProgrammingSnowflake Study Notes
Programming · 30 topics
ProgrammingApache Airflow Study Notes
Programming · 30 topics
Programmingdbt (Data Build Tool) Study Notes
Programming · 30 topics