← Back to Rust Course | Chapter 9: Collections | Lesson 4 of 6

The Entry API

The entry API lets you say "if this label doesn't have a value yet, give it a starting one," all in one tidy step.

Using entry with or_insert

.entry(key).or_insert(default) inserts the default value only if the key does not already exist, and returns a mutable reference to the value either way -- ready to use or modify immediately.

Example: Using entry with or_insert

markup
use std::collections::HashMap;

fn main() {
    let mut scores = HashMap::new();
    scores.entry("Alice").or_insert(0);
    println!("{:?}", scores.get("Alice"));
}

Counting Word Occurrences

A classic use of the entry API is counting occurrences: for each item, get its entry, default to 0 if missing, then increment through the returned mutable reference.

Example: Counting Word Occurrences

markup
use std::collections::HashMap;

fn main() {
    let words = ["a", "b", "a", "c", "b", "a"];
    let mut counts = HashMap::new();
    for word in words.iter() {
        let count = counts.entry(*word).or_insert(0);
        *count += 1;
    }
    println!("{:?}", counts.get("a"));
}

Lazy Defaults with or_insert_with

.or_insert_with(|| default()) only runs the closure to compute a default value if the key is actually missing, which avoids unnecessary work for expensive default values.

Example: Lazy Defaults with or_insert_with

markup
use std::collections::HashMap;

fn main() {
    let mut groups: HashMap<&str, Vec<i32>> = HashMap::new();
    groups.entry("evens").or_insert_with(Vec::new).push(2);
    groups.entry("evens").or_insert_with(Vec::new).push(4);
    println!("{:?}", groups.get("evens"));
}

Modifying Existing Values in Place

Because .entry().or_insert() returns a mutable reference, you can dereference it with * to update the value directly, which is the standard pattern for accumulating totals per key.

Example: Modifying Existing Values in Place

markup
use std::collections::HashMap;

fn main() {
    let mut totals: HashMap<&str, i32> = HashMap::new();
    for (name, amount) in vec![("tea", 3), ("coffee", 5), ("tea", 2)] {
        *totals.entry(name).or_insert(0) += amount;
    }
    println!("{:?}", totals.get("tea"));
}
Common Mistakes
  1. Manually checking with .contains_key() and then calling .insert() separately, instead of the more idiomatic single .entry() call.
  2. Forgetting .or_insert() returns a mutable reference, which you can then modify directly, like incrementing a counter.
  3. Using .or_insert(expensive_computation()) when the default value is costly to compute -- .or_insert_with() only runs the closure when needed.
Chapter Summary
  • .entry(key) returns a handle representing that key's slot, whether it currently exists or not.
  • .or_insert(default) inserts a default value only if the key is missing, and always returns a mutable reference to the value.
  • .or_insert_with(|| ...) lazily computes the default only when actually needed.
  • The entry API is the idiomatic way to implement counting or accumulating patterns with a HashMap.
🔒

Chapter Quiz — Complete all 6 topics to unlock

0/6 topics done

Complete these topics first:

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.