Hash Maps and Hash Sets
Creating a HashMap
HashMap<K, V> (imported via use std::collections::HashMap;) can be created empty, pre-allocated with a target capacity, initialized from a fixed-size array of (K, V) pairs, or collected from any iterator yielding (K, V) tuples.
Summary of HashMap<K, V> Construction Methods
| Constructor / Expression | Heap Allocation Behavior | Best Used When... |
|---|---|---|
HashMap::new() / HashMap::default() |
Zero heap allocation (capacity == 0) |
Starting an empty map whose size is unknown |
HashMap::with_capacity(n) |
Pre-allocates table for at least n elements without rehashing |
Expected number of entries n is known upfront |
HashMap::from([(k1, v1), (k2, v2)]) |
Single allocation sized for the array length | Initializing a map from literal key-value pairs |
iter.collect::<HashMap<K, V>>() |
Pre-allocates based on iter.size_hint().0 |
Building a map from .map(), .zip(), or filtered iterators |
HashMap::with_hasher(hash_builder) |
Zero allocation; uses custom BuildHasher |
Using a custom or deterministic hasher |
1. Empty and Pre-Allocated Maps (new and with_capacity)
When creating an empty map with HashMap::new() or HashMap::with_capacity(n), the compiler infers K and V from the first .insert(k, v) call (or from an explicit type annotation):
use std::collections::HashMap;
fn main() {
// Type `HashMap<&str, u16>` is inferred from the `.insert()` call below:
let mut ports = HashMap::with_capacity(8);
println!("Pre-allocated capacity: {}", ports.capacity());
ports.insert("http", 80);
ports.insert("https", 443);
println!("Ports: {ports:?}");
}
Pre-allocated capacity: 14
Ports: {"http": 80, "https": 443}
2. Array Literal Initialization (HashMap::from)
HashMap::from([(k1, v1), ...]) is the cleanest way to construct a populated map inline in Rust 2021 and 2024 editions. If duplicate keys appear in the array, later entries overwrite earlier ones:
use std::collections::HashMap;
fn main() {
let status_codes = HashMap::from([
(200_u16, "OK"),
(201, "Created"),
(404, "Not Found"),
(500, "Internal Server Error"),
]);
println!("200 -> {}", status_codes[&200]);
println!("Total entries: {}", status_codes.len());
}
200 -> OK
Total entries: 4
3. Collecting from Zipped or Transformed Iterators
Any iterator whose Item is a 2-tuple (K, V) (where K: Eq + Hash) can be collected into a HashMap<K, V>:
use std::collections::HashMap;
fn main() {
let headers = ["content-type", "cache-control", "x-request-id"];
let values = ["application/json", "no-cache", "req-991"];
// Pair two slices with `.zip()` and collect into a HashMap:
let header_map: HashMap<&str, &str> = headers.into_iter().zip(values).collect();
// Build an index map `(item -> index)` from `.enumerate()`:
let name_to_id: HashMap<&str, usize> = ["alice", "bob", "carol"]
.into_iter()
.enumerate()
.map(|(id, name)| (name, id))
.collect();
println!("content-type: {:?}", header_map.get("content-type"));
println!("bob's ID: {:?}", name_to_id.get("bob"));
}
content-type: Some(&"application/json")
bob's ID: Some(&1)