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)