What HashMap does

A hash map implemented with quadratic probing and SIMD lookup.

As a struct, HashMap bundles related fields into a single named record with a known layout. Each field has a fixed type and offset, so the size of an instance is the sum of its field sizes plus alignment padding. Construction follows ordinary Rust ownership rules: each owned field must itself be constructed or moved before the struct is well-formed, and the compiler will refuse to leave any field uninitialised. The full canonical path is std::collections::HashMap; bring it into scope with use std::collections::HashMap; or refer to it by its full path.

When to use it

Use HashMap when you need average-case O(1) insert / lookup / delete by key and you do not need keys to be ordered. Reach for BTreeMap if you need sorted iteration or range queries.

Annotated examples

Counting words with HashMap and the entry API

use std::collections::HashMap;

fn count_words(text: &str) -> HashMap<&str, u32> {
    let mut counts: HashMap<&str, u32> = HashMap::new();
    for word in text.split_whitespace() {
        // entry().or_insert(0) is the idiomatic counter-update pattern.
        // It returns &mut V, avoiding two hash lookups (contains + insert).
        *counts.entry(word).or_insert(0) += 1;
    }
    counts
}

fn main() {
    let counts = count_words("the quick brown fox the lazy fox");
    assert_eq!(counts["fox"], 2);
    assert_eq!(counts["the"], 2);
}

The entry API is the canonical way to do "increment or insert" in a Rust HashMap. It performs a single hash and returns a mutable reference to the value slot.

For deeper background, see the canonical Rust patterns reference for the broader context behind this section.

Pre-sizing with with_capacity for a known workload

use std::collections::HashMap;

fn build_index(records: &[(u64, String)]) -> HashMap<u64, String> {
    // with_capacity avoids repeated reallocation when you already know
    // approximately how many entries you'll insert. Pass the exact count
    // when you know it; round up otherwise.
    let mut index = HashMap::with_capacity(records.len());
    for (id, name) in records {
        index.insert(*id, name.clone());
    }
    index
}

with_capacity is the single biggest performance lever on HashMap when you know the size up front — it skips every intermediate resize and rehash.

Common pitfalls

The default hasher (SipHash 1-3) is randomised per process to defeat HashDoS — that's a feature in production but causes non-deterministic iteration order during tests. If you need reproducible output, sort by key when iterating, or swap to a different hasher with `HashMap::with_hasher`. Also note that holding a reference returned by `get` borrows the map immutably, which prevents you from also calling `insert` on it in the same scope.

For deeper background, see an in-depth Rust idioms cheat sheet for the broader context behind this section.

Performance & threading notes

Stack-allocated by default. Heap allocation only happens if a field is itself heap-allocated (Vec, String, Box). Cloning copies every field; for read access pass by reference. Send / Sync are automatically derived if every field is Send / Sync.