Start learning free

LESSON 134 OF 679 · DICTIONARIES

A Default for a Missing Key in a Rust HashMap

Lesson Read the full explanation

TL ; DR:

*map.get(key).unwrap_or(&0) gives the key's value, or 0 when the key is missing.


let points = HashMap::from([("Ana", 7)]);

println!("{}", *points.get("Ana").unwrap_or(&0));   // 7
println!("{}", *points.get("Ben").unwrap_or(&0));   // 0


Full lesson:

A missing key often means "none yet". A player with no points yet has 0 points.

points["Ben"] can't say that. It panics.

get gives an Option, as in Option & Some. It is Some(&7) for Ana and None for Ben.

unwrap_or(&0) takes the reference inside, or a reference to 0. The * in front turns it into a plain number.

Reading this way doesn't add the key. points still has one key afterwards.

With a String key in a variable, pass &name to get.


Your task

stock counts the fruit in a shop. The code reads and prints the pears.

There are no plums yet. Read "plums" with get and unwrap_or(&0). Store it in plums.

Then print the plums line, the same way as the pears line.

Expected output:

We have 2 pears
We have 0 plums
STEP 1 OF 2
    Ctrl + Enter to check

    RUST · DICTIONARIES

    Dictionary Default Value in Rust, explained

    When a missing key means none

    Often a missing key just means "none yet". A shop whose stock map has no plums has 0 plums. But stock["plums"] can't express that: indexing a missing key panics. The tool for this is the get method.

    get doesn't return the value directly. It returns an Option: Some(&5) when the key exists (a reference to the value inside the map), and None when it doesn't. For a map with only apples, stock.get("apples") prints as Some(5) and stock.get("plums") as None.

    let stock = HashMap::from([("apples", 5)]);
    println!("{}", *stock.get("apples").unwrap_or(&0));   // 5
    println!("{}", *stock.get("plums").unwrap_or(&0));    // 0
    

    Reading the one-liner

    Three small pieces make up *stock.get("plums").unwrap_or(&0):

    1. get("plums") gives the Option.
    2. unwrap_or(&0) takes the reference out of a Some, or uses a reference to 0 when the option is None. It must be &0 and not 0, because it has to be the same type as what get hands back: a reference.
    3. The * in front reads the number behind the reference, turning a &i32 into a plain i32.

    Without the *, assigning the result to a variable declared as i32 is a compile error: the compiler reports "expected i32, found &{integer}" and suggests dereferencing the borrow.

    Reading this way doesn't add anything to the map. After both lookups above, stock.len() is still 1. With a key in a String variable, pass a reference to get, as in get(&name).

    The task, step by step

    The starter code already reads the pears with stock["pears"], which is safe because pears are in the map. There are no plums, so the first step looks up "plums" with get, applies unwrap_or(&0), puts * in front, and stores the number in plums. The second step prints a line like the pears line.

    let stock = HashMap::from([("apples", 5), ("pears", 2)]);
    let pears = stock["pears"];
    println!("We have {} pears", pears);
    let plums = *stock.get("plums").unwrap_or(&0);
    println!("We have {} plums", plums);
    

    It prints:

    We have 2 pears
    We have 0 plums
    

    Why an Option

    Rust has no null value. When a lookup might find nothing, the result type says so: Option forces you to decide what happens for None before you can use the number. unwrap_or is the shortest decision, "use this default". You could also write match or if let to run different code for the two cases, which is useful when the default isn't a plain number. For counting, though, 0 is exactly right: a missing key means none so far, so the default and the real value agree.

    Following the lookups

    In the task, the map has apples (5) and pears (2). The pears line works with plain indexing because the key is certainly there. For plums, get("plums") is None, unwrap_or(&0) turns it into a reference to 0, and * reads that 0. The final print then fills the placeholder in We have {} plums with 0. Pears would have worked with get too, and in real programs you would use get whenever the key is not guaranteed.

    Common mistakes

    • Using [] for a key that might be missing. It panics instead of giving a default.
    • Writing unwrap_or(0) without the &, which is a type mismatch.
    • Forgetting the *, which leaves a reference where a number is expected.
    • Using plain unwrap(), which panics on None just like indexing.

    Key takeaways

    • map.get(key) returns an Option: Some for a present key, None for a missing one.
    • *map.get(key).unwrap_or(&0) is the value, or 0 for a missing key.
    • Reading with get never adds a key to the map.
    Keep going with Rust500+ step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free