Start learning free

LESSON 129 OF 671 · DICTIONARIES

Checking for a Key in a Go Map

Lesson Read the full explanation

TL ; DR:

The comma-ok lookup tells you whether a map has a key. Its ok is true when the key is there, so it goes in an if.


capitals := map[string]string{"France": "Paris", "Japan": "Tokyo"}

if _, ok := capitals["Japan"]; ok {
    fmt.Println(capitals["Japan"])   // Tokyo
}

if _, ok := capitals["Spain"]; !ok {
    fmt.Println("No Spain")          // No Spain
}


Full lesson:

You met this lookup in Maps & the ok Idiom. A missing key gives the zero value, here "". And ok is false.

Only ok tells a missing key from a key that holds "". So don't check with capitals["Spain"] == "".

The _ throws the value away. This check needs only ok.

The lookup can sit in the if line, before a ;. Then ok exists only inside that if.

!ok asks the opposite. It is true when the key is missing.

A value is not a key

A lookup looks only at the keys. capitals["Paris"] gives an ok of false, because "Paris" is a value.

A key must match exactly, upper and lower case too. capitals["japan"] misses as well.


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 a comma-ok lookup and !ok. 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

    GO · DICTIONARIES

    Dictionary Key Check in Go, explained

    Why a plain lookup isn't enough

    In Go, reading a key that isn't in a map does not fail. It gives the zero value of the value type: 0 for an int, "" for a string, false for a bool. That is convenient, but it means the value alone can't tell you whether the key exists. A map that holds "X": "" and a map with no "X" both answer "" to m["X"].

    So a check like capitals["Spain"] == "" is unreliable. It is true for a missing key, but also for a key whose value really is an empty string.

    The comma-ok lookup

    A lookup can return two values: the value and a bool that is true only when the key is in the map. By convention the second one is named ok.

    capitals := map[string]string{"France": "Paris", "Japan": "Tokyo"}
    
    if _, ok := capitals["Japan"]; ok {
        fmt.Println(capitals["Japan"])   // Tokyo
    }
    if _, ok := capitals["Spain"]; !ok {
        fmt.Println("No Spain")          // No Spain
    }
    

    Three details are worth knowing:

    • The _ throws the value away. This check only needs ok, and Go would reject an unused variable, so the blank identifier is the way to ignore it.
    • The lookup can sit in the if line, before a ;. It runs first, and ok exists only inside that if (and its else).
    • !ok asks the opposite question: it is true when the key is missing.

    With a map that stores an empty string, the difference shows. For empty := map[string]string{"X": ""}, the lookup v, ok := empty["X"] gives "" and true, while a lookup of "Y" gives "" and false. The comparison == "" is true for both, so only ok separates them.

    When you need the value as well, keep it instead of throwing it away. The value and ok come from the same lookup, so there is no second search:

    if capital, ok := capitals["Japan"]; ok {
        fmt.Println("The capital is", capital)   // The capital is Tokyo
    } else {
        fmt.Println("Unknown")
    }
    

    For "Peru" the same code prints Unknown.

    A value is not a key

    A lookup looks only at the keys. capitals["Paris"] gives an ok of false, because "Paris" is a value, not a key. Keys must also match exactly, upper and lower case included, so capitals["japan"] misses as well. Checking a value is a different job and needs a loop over the map.

    The task: pets and their kinds

    In pets, each key is a pet's name and its value is the kind of animal. The task has two checks.

    1. If "Tom" is a key, print Tom is a followed by Tom's kind. Use the comma-ok lookup in the if line, and print "Tom is a " + pets["Tom"] inside.
    2. Check that "cat" is not a key, with !ok, and print cat is not a key. "cat" does appear in the map, but only as a value: it is Tom's kind. The lookup looks at keys only, so it misses.
    pets := map[string]string{"Rex": "dog", "Tom": "cat", "Polly": "parrot"}
    if _, ok := pets["Tom"]; ok {
        fmt.Println("Tom is a " + pets["Tom"])
    }
    if _, ok := pets["cat"]; !ok {
        fmt.Println("cat is not a key")
    }
    

    The output is:

    Tom is a cat
    cat is not a key
    

    Common mistakes

    • Checking pets["cat"] for a name when "cat" is a kind. It is a value, so the lookup misses.
    • Using the value in the if condition instead of ok. A stored zero value then looks like a missing key.
    • Using ok after the if block. A variable declared in the if line isn't visible outside it.

    Key takeaways

    • A missing key gives the zero value, so only ok tells a missing key from a stored zero value.
    • if _, ok := m[k]; ok { ... } runs when the key is there; use !ok when it isn't.
    • Lookups check keys, never values, and keys match exactly.
    Keep going with Go500+ step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free