Hash Maps and Hash Sets

Inserting and Updating Values

HashMap<K, V> provides several ways to insert new key-value pairs and update existing values, depending on whether you want to overwrite unconditionally (.insert()), keep the existing value (.entry(k).or_insert()), or transform the existing value in place.

Behavior of map.insert(k, v)

pub fn insert(&mut self, k: K, v: V) -> Option<V>
  1. If k is not in the map: Inserts (k, v) and returns None.
  2. If an equal key k_old == k is already in the map:
    • Replaces the value with v and returns Some(old_value).
    • Does NOT update the existing key k_old in the table! This nuance matters for types where k1 == k2 does not mean k1 and k2 are identical (such as case-insensitive string wrappers or structs comparing only by ID).
use std::collections::HashMap;

fn main() {
    let mut timeouts = HashMap::new();

    // 1. First insertion of "db" returns `None`:
    let prev1 = timeouts.insert("db", 3_000_u64);
    println!("1st insert of 'db' returned: {prev1:?}");

    // 2. Second insertion of "db" overwrites 3000 with 5000 and returns `Some(3000)`:
    let prev2 = timeouts.insert("db", 5_000);
    println!("2nd insert of 'db' returned: {prev2:?}");
    println!("Current 'db' timeout:        {}", timeouts["db"]);
}
1st insert of 'db' returned: None
2nd insert of 'db' returned: Some(3000)
Current 'db' timeout:        5000

Ownership of Keys and Values Passed to insert()

Calling map.insert(k, v) moves both k and v into the HashMap. If k or v is a non-Copy type like String, the original variables cannot be used after insert unless cloned:

use std::collections::HashMap;

fn main() {
    let key = String::from("region");
    let val = String::from("ap-south-1");

    let mut config = HashMap::new();
    config.insert(key, val); // Moves `key` and `val` into `config`

    println!("Stored region: {}", config["region"]);
}
Stored region: ap-south-1

Comparing the Four Update Patterns on HashMap<K, V>

Update Goal Idiomatic Expression Key Lookup Count
Overwrite unconditionally (or insert if missing) map.insert(k, new_val) 1
Insert only if missing (keep existing value) map.entry(k).or_insert(default_val) 1
Modify only if already present (do nothing if missing) if let Some(v) = map.get_mut(&k) { *v += 1; } 1
Modify if present, or insert default if missing *map.entry(k).or_insert(0) += 1; or map.entry(k).and_modify(f).or_insert(init) 1
Merge another map/iterator (overwriting matching keys) map.extend(other_map) 1 per item
use std::collections::HashMap;

fn main() {
    let mut stock = HashMap::from([("ssd", 10_u32), ("ram", 25)]);

    // 1. Update only if already present:
    if let Some(qty) = stock.get_mut("ssd") {
        *qty += 5;
    }

    // 2. Bulk insert/overwrite from an array or iterator via `extend`:
    stock.extend([("gpu", 4), ("ram", 30)]);

    println!("ssd={}, ram={}, gpu={}", stock["ssd"], stock["ram"], stock["gpu"]);
}
ssd=15, ram=30, gpu=4