Is the key there
In the previous lesson we found out that when a name is not in the phone book, a map answers with the zero value. That is usually handy, but sometimes it gets in the way. In a map of player scores, the value 0 can be a real result. A plain read cannot tell it apart from a key that is not there:
package main
import "fmt"
func main() {
scores := map[string]int{"ann": 0, "bob": 7}
fmt.Println(scores["ann"], scores["max"]) // 0 0
}Here are two different cases:
- the player
annplayed and scored zero points; - the player
maxis not in the map at all.
Both reads return 0, because a missing key reads as the zero value. It is like asking a phone book for a number and hearing "0": you cannot tell whether that is the number or the person is not in the book.
Two values from a read
A read from a map can return a second value of type bool. It is true if the key is there and false if it is not. This form is called the comma ok idiom, after the comma between the two variables:
scores := map[string]int{"ann": 0, "bob": 7}
v, ok := scores["ann"]
fmt.Println(v, ok) // 0 true
w, found := scores["max"]
fmt.Println(w, found) // 0 falseLet's walk through the example line by line:
v, ok := scores["ann"]reads two values. The key"ann"is there, sookistrue, thoughvis0: what counts is the key, not its value.fmt.Println(v, ok)prints0 true.w, found := scores["max"]reads a missing key. The first value is the zero value, as with a plain read, and the second isfalse.fmt.Println(w, found)prints0 false.
The second variable can have any name: ok is a convention, not a keyword. If the value itself is not needed, write _ in place of the first variable: _, ok := scores["max"].
Interviewers like to ask: "How do you check whether a key is in a map?" The answer is to read two values and look at the second.
When comma ok is needed
The choice depends on whether the zero value can be a real one:
- it can—zero points, an empty name,
falsein amap[string]bool—so you need comma ok; - it cannot—for example, a price is always above zero—so a plain read and a zero check are enough.
A check in if
Most often, comma ok sits in the init statement of an if. The variables v and ok are then visible only inside the if and stay out of the rest of the code:
scores := map[string]int{"bob": 7}
if v, ok := scores["bob"]; ok {
fmt.Println("bob:", v) // bob: 7
}
if _, ok := scores["max"]; !ok {
fmt.Println("no max") // no max
}Let's walk through both ifs:
- The key
"bob"is there, so the firstifprints his score:bob: 7. - The key
"max"is not,okisfalse, and the secondifprintsno max.
A map as a set
Sometimes the zero value of a missing key is exactly what helps. That is how a set works: a collection of values without repeats. Go has no separate set type, and interviewers often ask how to make one. The answer is a map with bool values: seen := map[string]bool{}.
You work with such a set like this:
- you add a value with
seen[w] = true; - you check it with a plain read:
if seen[w]; - nobody writes
falseinto such a map, sofalseon a read means one thing: the key is not in the set.
Comma ok is not needed here. This makes it handy to filter out repeats: if seen[w] is already true, the value came up before.
Common mistake
The presence of a key is checked by comparing with zero:
scores := map[string]int{"ann": 0}
if scores["ann"] == 0 { // ✗
fmt.Println("no ann")
}The program prints no ann, though "ann" is in the map: its value 0 equals a missing key's zero value. This check mixes up a player with zero points and a player who is not there. Check the second value instead: if _, ok := scores["ann"]; !ok.
Key points
v, ok := m[k]returns the value andtrueif the key is there, or the zero value andfalseif it is not.- Comma ok is needed when the zero value can be a real one, like zero points.
- A set in Go is a
map[T]bool: add withseen[x] = true, check withif seen[x].
Subscribe to take the course
The course is free. Sign in with Telegram and subscribe to the channel to open every lesson.