Rust’s HashMap is one of the most commonly used data structures when you need to associate keys with values. It is part of the standard library and provides an efficient way to store and retrieve data using a hashing mechanism.
A HashMap
HashMap Characteristics (Rust)
- Each key appears only once (keys are unique)
- Inserting a value with an existing key replaces the old value
- The insert method returns the old value (if the key already existed)
- Stores data as key-value pairs
- Does not guarantee order of elements (unordered collection)
- Provides fast lookup, insertion, and deletion (average O(1))
- Keys must implement Eq and Hash traits
Example
use std::collections::HashMap;
fn main() {
let mut map = HashMap::new();
map.insert("a", 1);
let old = map.insert("a", 2);
println!("Old value: {:?}", old);
println!("Current value: {:?}", map.get("a"));
}
Output:
Old value: Some(1)
Current value: Some(2)
This example shows an important behavior: inserting a value with an existing key replaces the previous value and returns it.
Ownership and Borrowing
One important aspect of Rust’s HashMap is how it handles ownership.
- If you insert owned data (like String), the map takes ownership.
- If you use references (like &str), you must ensure they live long enough.
let mut map = HashMap::new();
let key = String::from("name");
map.insert(key, 42);
// key can no longer be used here (ownership moved)
Accessing Values Safely
When retrieving values, HashMap returns an Option:
match map.get("a") {
Some(value) => println!("Value: {}", value),
None => println!("Key not found"),
}
This forces you to handle missing keys safely, avoiding runtime errors.
Using entry() for Efficient Updates
A very powerful feature is the entry() API, which avoids duplicate lookups:
let mut map = HashMap::new();
map.entry("a").or_insert(0);
map.entry("a").and_modify(|v| *v += 1);
println!("{:?}", map);
This is especially useful for counting:
let text = "hello world hello";
let mut counts = HashMap::new();
for word in text.split_whitespace() {
*counts.entry(word).or_insert(0) += 1;
}
println!("{:?}", counts);
Performance Considerations
- Average complexity is O(1) for insert, lookup, and delete
- Internally uses hashing
- May reallocate when growing (handled efficiently)
Unlike some other collections, HashMap does not preserve order. If you need ordering, consider alternatives like BTreeMap.
When to Use HashMap
- You need fast lookups by key
- Order does not matter
- You want to ensure key uniqueness
- You are building frequency maps or indexes
Conclusion
Rust’s HashMap is a powerful and efficient data structure that combines performance with safety. Thanks to ownership rules and the type system, it prevents many common bugs found in other languages.
Understanding how insertion, ownership, and retrieval work will help you use HashMap effectively in real-world Rust applications.