TL;DR:
HashMap<K, V>is Rust's standard hash map, a collection that stores key-value pairs and provides O(1) average-time lookup, insertion, and deletion. Keys must implementHashandEq. Like all Rust collections,HashMapowns its keys and values, inserting a value moves ownership into the map. Rust'sHashMapuses the SipHash algorithm by default, which is DoS-resistant but slightly slower than non-cryptographic alternatives likeFxHashMaporAHashMapfrom popular crates.
What Is HashMap<K, V> in Rust?
HashMap<K, V> maps keys of type K to values of type V with O(1) average-time access ; Rust's equivalent of Python's dict or JavaScript's Map.
use std::collections::HashMap;
fn main() {
let mut scores: HashMap<String, u32> = HashMap::new();
// Insert
scores.insert("Alice".to_string(), 100);
scores.insert("Bob".to_string(), 85);
scores.insert("Carol".to_string(), 92);
// Lookup; returns Option<&V>
if let Some(score) = scores.get("Alice") {
println!("Alice's score: {score}");
}
// Direct access; panics if key missing
println!("{}", scores["Bob"]);
// Check existence
println!("{}", scores.contains_key("Dave")); // false
// Length
println!("{}", scores.len()); // 3
}How Does Ownership Work With HashMap?
HashMap takes ownership of inserted keys and values. For Copy types (integers), values are copied in. For heap types (String, Vec), values are moved in.
use std::collections::HashMap;
fn main() {
let key = String::from("color");
let value = String::from("blue");
let mut map = HashMap::new();
map.insert(key, value);
// println!("{key}"); // COMPILE ERROR: key was moved into the map
// println!("{value}"); // COMPILE ERROR: value was moved
// Use references to avoid moving:
map.insert("size".to_string(), "large".to_string());
// .get() returns &V; borrows from the map, doesn't move
let color: Option<&String> = map.get("color");
}What Are the Key HashMap Operations?
entry() is the most powerful API, it lets you insert-or-update without a double lookup.
use std::collections::HashMap;
fn main() {
let text = "hello world hello rust hello";
let mut word_count: HashMap<&str, u32> = HashMap::new();
for word in text.split_whitespace() {
// entry().or_insert(); insert default if absent, return &mut V
let count = word_count.entry(word).or_insert(0);
*count += 1;
}
println!("{:?}", word_count);
// {"hello": 3, "world": 1, "rust": 1}
// or_insert_with; lazily compute default (avoids allocation if present)
word_count.entry("rust").or_insert_with(|| 0);
// and_modify; update only if present
word_count.entry("hello").and_modify(|c| *c *= 2);
// Remove
let removed = word_count.remove("world"); // Some(1)
// Iterate
for (word, count) in &word_count {
println!("{word}: {count}");
}
}How Do You Build a HashMap From an Iterator?
Collect an iterator of (key, value) tuples directly into a HashMap using .collect().
use std::collections::HashMap;
fn main() {
// From two vecs zipped together
let keys = vec!["a", "b", "c"];
let vals = vec![1, 2, 3];
let map: HashMap<&str, i32> = keys.into_iter().zip(vals).collect();
// From transforming a vec
let words = vec!["hello", "world", "rust"];
let lengths: HashMap<&str, usize> = words
.iter()
.map(|&w| (w, w.len()))
.collect();
println!("{:?}", lengths); // {"hello": 5, "world": 5, "rust": 4}
}What Other Map Types Are Available?
| Type | Use case |
|---|---|
HashMap<K, V> | Default ; SipHash, DoS-resistant |
BTreeMap<K, V> | Keys always sorted; O(log n) access |
IndexMap<K, V> (indexmap crate) | Preserves insertion order |
FxHashMap (rustc-hash crate) | Faster hash, not DoS-resistant, use in trusted environments |
AHashMap (ahash crate) | Fast alternative used by many frameworks |
DashMap (dashmap crate) | Concurrent hash map, safe across threads |
BTreeMap is the right choice when you need sorted iteration over keys, or when implementing a range-query structure.
Frequently Asked Questions
HashMap uses hashing, the bucket a key lands in depends on its hash, not insertion time. If you need ordered iteration, use BTreeMap (sorted by key) or IndexMap (preserves insertion order).
Any type implementing Hash + Eq. This includes all primitive types, String, &str, tuples of hashable types, and arrays. Floats (f32, f64) do NOT implement Hash (because NaN != NaN): you cannot use them as keys. Use an ordered integer representation instead.
.get("key").unwrap_or(&default) or .get("key").copied().unwrap_or(0) for Copy types. For the insert-if-absent pattern, use .entry("key").or_insert(default).
No, HashMap is not Sync. For concurrent access, use DashMap (from the dashmap crate), or wrap in Arc<Mutex<HashMap<K, V>>>. For read-heavy workloads, Arc<RwLock<HashMap<K, V>>> allows concurrent reads.
Sources
- The Rust Book ; Storing Keys with Associated Values in Hash Maps
- std::collections::HashMap ; Rust Standard Library
Related Glossary Terms
- Ownership: Inserted keys and values are moved into the map
- Generic:
HashMap<K, V>is generic over key and value types - Iterator: HashMaps can be built from and iterated with iterators
- Vec:
VecandHashMapare the two most-used collections
