Skip to content
HashMap
step 1/5

Reading — step 1 of 5

Learn

~2 min readCollections

HashMap

HashMap<K, V> is Rust's hash table — constant-time key→value storage, the engine behind every counting, grouping, and have-I-seen-it problem. The API differs from other languages in one philosophically Rust way: a missing key is not an error and not a zero — it's an Option, and you say what happens.

The basics

use std::collections::HashMap;          // the one import you'll forget

let mut ages: HashMap<String, i32> = HashMap::new();
ages.insert(String::from("alice"), 30);
ages.insert(String::from("bob"), 25);

ages.insert(String::from("bob"), 26);   // same key: overwrites, no complaint
ages.remove("alice");
ages.len();

Reading: Option again

match ages.get("bob") {
    Some(age) => println!("bob is {age}"),
    None => println!("no bob on record"),
}

if let Some(age) = ages.get("bob") {     // terser when you only care about Some
    println!("{age}");
}

get returns Option<&V> — the presence question and the value arrive together, and the compiler won't let you use the value without acknowledging the None case. Where Go silently hands you a zero and a separate ok flag you might forget to check, Rust bakes the check into the type. Same idea, enforced.

Direct indexing exists (ages["bob"]) and panics on missing keys — same convenient-vs-careful split as Vec.

entry(): the API everyone falls in love with

The counting problem — "increment, but the key might not exist yet" — has a dedicated, beautiful answer:

let mut counts: HashMap<String, i32> = HashMap::new();
for word in words {
    *counts.entry(word).or_insert(0) += 1;
}

Read it inside-out: entry(word) is a handle to the slot (existing or vacant); .or_insert(0) fills a vacant slot with 0 and returns a mutable reference either way; *… += 1 increments through that reference. One line, one lookup, no race between "check" and "insert." This is the counting idiom — you will type it in interviews.

Iteration: random on purpose

for (name, age) in &ages {
    println!("{name}: {age}");
}

Order is arbitrary and varies run to run (HashDoS resistance, same story as Go). When output must be sorted for a grader: collect and sort first —

let mut keys: Vec<_> = counts.keys().collect();
keys.sort();

Your exercise: Distinct Words

Count distinct words in the input. A set is what you want, and Rust has a real one — HashSet<String> (a HashMap with no values, same use std::collections:: home):

let mut seen = HashSet::new();
for word in words {
    seen.insert(word);        // duplicates are simply ignored
}
println!("{}", seen.len());

Insert everything, print len() — duplicates cost nothing because sets don't count enthusiasm. If you'd rather practice this lesson's star, tally into a HashMap with the entry idiom instead and print its len(); identical answer, and now you've typed the counting one-liner once before the day an exercise demands the counts themselves.

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…