Start learning free

LESSON 133 OF 679 · DICTIONARIES

Checking for a Key in a Rust HashMap

Lesson Read the full explanation

TL ; DR:

Call map.contains_key(key) to ask whether a HashMap has a key. It returns true or false, so it goes in an if.


let capitals = HashMap::from([("France", "Paris"), ("Japan", "Tokyo")]);

if capitals.contains_key("Japan") {
    println!("{}", capitals["Japan"]);   // Tokyo
}

if !capitals.contains_key("Spain") {
    println!("No Spain");                // No Spain
}


Full lesson:

Reading a missing key with [] panics. capitals["Spain"] stops the program.

So check first. capitals.contains_key("Spain") is true when "Spain" is a key. It is false when it isn't.

Put ! in front for the opposite. !capitals.contains_key("Spain") is true here.

A value is not a key

contains_key looks only at the keys. capitals.contains_key("Paris") is false, because "Paris" is a value.

When the key is a String in a variable, pass a reference, as in contains_key(&name).

A key must match exactly, upper and lower case too. capitals.contains_key("japan") is false.


Your task

In pets, each key is a pet's name, and its value is the pet's kind.

First, check whether "Tom" is a key of pets. If it is, print Tom is a followed by Tom's kind.

Then check that "cat" is not a key, with ! and contains_key. If so, print cat is not a key.

"cat" is in pets, but only as a value. It is Tom's kind.

Expected output:

Tom is a cat
cat is not a key
STEP 1 OF 2
    Ctrl + Enter to check

    RUST · DICTIONARIES

    Dictionary Key Check in Rust, explained

    Why check first

    Reading a key that isn't in a HashMap with square brackets panics and stops the program. With capitals holding France and Japan, capitals["Spain"] ends with the message "no entry found for key". So when a key may be missing, ask first.

    The method contains_key answers that question. It returns true when the key is in the map and false when it isn't:

    let capitals = HashMap::from([("France", "Paris"), ("Japan", "Tokyo")]);
    if capitals.contains_key("Japan") {
        println!("{}", capitals["Japan"]);   // Tokyo
    }
    if !capitals.contains_key("Spain") {
        println!("No Spain");                // No Spain
    }
    

    Inside the first if, capitals["Japan"] can't panic, because the check just proved the key is there. Put ! in front for the opposite: !capitals.contains_key("Spain") is true here. (In a file of your own, a HashMap needs use std::collections::HashMap; at the top.)

    A value is not a key

    contains_key looks only at the keys. In capitals, contains_key("Paris") is false, because "Paris" is a value, not a key. Matching is exact, including upper and lower case, so contains_key("japan") is false too.

    String keys in variables

    When the map's keys are String values and the key you look for is in a String variable called name, pass a reference: contains_key(&name). The method only borrows the key to compare it, so name is still usable afterwards. A literal like "Japan" can be passed directly, because a map with &str keys is searched by &str, and even a map with String keys accepts a &str for lookups.

    The task, step by step

    The map pets goes from each pet's name to its kind: Rex is a dog, Tom a cat, Polly a parrot. The first step checks pets.contains_key("Tom") and prints Tom's kind with pets["Tom"] inside the if. The second step checks that "cat" is not a key. It is a value, Tom's kind, so !pets.contains_key("cat") is true and the message prints.

    let pets = HashMap::from([("Rex", "dog"), ("Tom", "cat"), ("Polly", "parrot")]);
    if pets.contains_key("Tom") {
        println!("Tom is a {}", pets["Tom"]);
    }
    if !pets.contains_key("cat") {
        println!("cat is not a key");
    }
    

    It prints:

    Tom is a cat
    cat is not a key
    

    Another way: get

    When you want to use the value as well as know the key exists, get does both in one step, so you don't search the map twice. if let Some(c) = capitals.get("Japan") { println!("{}", c); } prints Tokyo, and for "Spain" the if let body is skipped. A match with a None arm can print "unknown" for the missing key. For this lesson, though, the point is the plain yes-or-no question, and contains_key is the clearest way to ask it. The next lessons build on get.

    Keys and values side by side

    It helps to picture the map as two columns. The left column holds the names Rex, Tom and Polly, which are the keys. The right column holds dog, cat and parrot, which are the values. Every question you ask with contains_key is about the left column only. To ask about the right column you would have to look through the values, which is a different operation. In the task, the word "cat" lives in the right column, so as a key it is missing, and that is exactly what the second check proves.

    Common mistakes

    • Reading with [] without checking, which panics for a missing key.
    • Checking a value instead of a key, as with contains_key("cat") here.
    • Mismatched capitalisation between the key you wrote and the one stored.

    Key takeaways

    • map.contains_key(key) returns true or false and looks only at keys.
    • Check before using [], since a missing key panics.
    • For a String variable, pass &name.
    Keep going with Rust500+ step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free