Hash Maps and Hash Sets

entry().or_insert()

The map.entry(key).or_insert(default) pattern ensures a key exists in a HashMap<K, V>—inserting default if the key is absent—and returns a mutable reference &mut V to the value in the map so it can be read or modified in place.

Signature and Execution Flow

impl<'a, K, V> Entry<'a, K, V> {
    pub fn or_insert(self, default: V) -> &'a mut V
}
let slot: &mut V = map.entry(key).or_insert(default);
                       │
                       ├── Key already present ──> drops `default`, returns `&mut existing_val`
                       └── Key absent          ──> inserts `(key, default)`, returns `&mut new_val`

Because or_insert returns &'a mut V, dereferencing the return value (*map.entry(k).or_insert(0) += 1) modifies the value directly inside its bucket without a second hash lookup.

Initializing Default Values and Mutating Through &mut V

use std::collections::HashMap;

fn main() {
    let mut settings = HashMap::from([("retries", 3_u32)]);

    // 1. Key "retries" already exists -> keeps 3, ignores 10:
    settings.entry("retries").or_insert(10);

    // 2. Key "timeout_sec" does not exist -> inserts 30:
    settings.entry("timeout_sec").or_insert(30);

    // 3. Mutate the returned `&mut u32` reference directly:
    let retries_ref: &mut u32 = settings.entry("retries").or_insert(0);
    *retries_ref += 2;

    println!(
        "retries = {}, timeout_sec = {}",
        settings["retries"], settings["timeout_sec"]
    );
}
retries = 5, timeout_sec = 30

Using .or_default() When default Is V::default()

Whenever the fallback value passed to .or_insert(...) is 0, false, "", Vec::new(), or Default::default(), prefer .or_default() for brevity (and to avoid evaluating Default::default() when the key is already occupied):

use std::collections::HashMap;

fn main() {
    let mut groups: HashMap<&str, Vec<&str>> = HashMap::new();

    for (dept, employee) in [("eng", "alice"), ("sales", "bob"), ("eng", "carol")] {
        // Inserts an empty `Vec` if `dept` is missing, then pushes `employee`:
        groups.entry(dept).or_default().push(employee);
    }

    println!("eng:   {:?}", groups["eng"]);
    println!("sales: {:?}", groups["sales"]);
}
eng:   ["alice", "carol"]
sales: ["bob"]

Eager Evaluation Caveat of or_insert(default)

Because or_insert(default) is a regular method call, Rust evaluates the argument default before calling or_insert—even when the key is already present in the map! Keep or_insert(val) for cheap stack values (integers, booleans, None, &str), and use .or_insert_with(|| ...) or .or_default() when constructing the fallback value allocates or performs work.