← 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.
Syntax
rust
map.entry(key).or_insert(default);
*map.entry(key).or_insert(default) += 1;
map.entry(key).or_default().push(value);

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
// Bring `std::collections::HashMap` into scope
use std::collections::HashMap;

// Entry point: execution of the program starts here
fn main() {
    // Declare a mutable variable `scores`, initialized to `HashMap::new()`
    let mut scores = HashMap::new();
    scores.entry("Alice").or_insert(0);
    // Print "{:?}" to the console, substituting in `scores.get("Alice")` (with a trailing newline)
    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
// Bring `std::collections::HashMap` into scope
use std::collections::HashMap;

// Entry point: execution of the program starts here
fn main() {
    // Declare an immutable variable `words`, set to `["a", "b", "a", "c", "b", "a"]`
    let words = ["a", "b", "a", "c", "b", "a"];
    // Declare a mutable variable `counts`, initialized to `HashMap::new()`
    let mut counts = HashMap::new();
    // Loop over `words.iter()`, binding each item to `word`
    for word in words.iter() {
        // Declare an immutable variable `count`, set to `counts.entry(*word).or_insert(0)`
        let count = counts.entry(*word).or_insert(0);
        *count += 1;
    }
    // Print "{:?}" to the console, substituting in `counts.get("a")` (with a trailing newline)
    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
// Bring `std::collections::HashMap` into scope
use std::collections::HashMap;

// Entry point: execution of the program starts here
fn main() {
    // Declare a mutable variable `groups` (a `HashMap<&str, Vec<i32>>`), initialized to `HashMap::new()`
    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);
    // Print "{:?}" to the console, substituting in `groups.get("evens")` (with a trailing newline)
    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
// Bring `std::collections::HashMap` into scope
use std::collections::HashMap;

// Entry point: execution of the program starts here
fn main() {
    // Declare a mutable variable `totals` (a `HashMap<&str, i32>`), initialized to `HashMap::new()`
    let mut totals: HashMap<&str, i32> = HashMap::new();
    // Loop over `vec![("tea", 3), ("coffee", 5), ("tea", 2)]`, binding each item to `(name, amount)`
    for (name, amount) in vec![("tea", 3), ("coffee", 5), ("tea", 2)] {
        *totals.entry(name).or_insert(0) += amount;
    }
    // Print "{:?}" to the console, substituting in `totals.get("tea")` (with a trailing newline)
    println!("{:?}", totals.get("tea"));
}
Related Topics
{# common_mistakes/chapter_summary/browser_support: on Hindi pages the view already swaps in the hi_ translation fields (or blanks these out if untranslated), so this renders correctly for both languages without a lang_code check here. #}
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.