A missing key means "none yet"
Often a key that is not in the map has a natural meaning. A shop with no plums has 0 plums. A word that hasn't been counted yet has been seen 0 times. Go makes that case easy: reading a missing key never fails, and it gives the zero value of the value type.
stock := map[string]int{"apples": 5}
fmt.Println(stock["apples"]) // 5
fmt.Println(stock["plums"]) // 0
The zero value of an int is 0, so a plain lookup already reads with 0 as the default. No if is needed.
Reading doesn't add the key
A lookup only reads. After stock["plums"], the map still has exactly one key: len(stock) is still 1. Only an assignment such as stock["plums"] = 3 adds a key.
Zero values by type
The default depends on the value type of the map:
| Value type | Missing key gives |
|---|---|
int | 0 |
string | "" (empty text) |
bool | false |
Printing names["a"] on an empty map[string]string shows an empty string, and flags["a"] on a map[string]bool shows false.
This also makes a counter easy to write. For a key that doesn't exist yet, stock["plums"] = stock["plums"] + 3 reads 0, adds 3 and stores the result. The map then has 2 keys and stock["plums"] is 3. No separate step to create the key is needed.
When you want a different default
The zero value isn't always the right answer. To get something else, use the comma-ok form and replace the value when the key is missing. Here a missing key gives -1:
plums, ok := stock["plums"]
if !ok {
plums = -1
}
fmt.Println(plums) // -1
The same form is how you tell a missing key from a key that really stores a zero. If stock["pears"] was set to 0, a plain lookup gives 0 for it, just as it does for "figs", which was never added. When the difference matters, check ok.
The task: pears and plums
stock counts the fruit in a shop: 5 apples and 2 pears, and no plums. The starter code already reads and prints the pears. Your job is to do the same for the plums.
- Read
"plums"with a plain lookup and store it inplumswith:=. The key is missing, and the zero value, 0, is exactly the default we want. - Print the plums line the same way as the pears line, with
plumsin place ofpears.
stock := map[string]int{"apples": 5, "pears": 2}
pears := stock["pears"]
fmt.Println("We have", pears, "pears")
plums := stock["plums"]
fmt.Println("We have", plums, "plums")
The output is:
We have 2 pears
We have 0 plums
Common mistakes
- Expecting an error or a crash for a missing key. Go gives the zero value and carries on.
- Assuming a printed
0means the key exists. It may be a missing key, so checkokwhen that matters. - Copying the pears line and forgetting to change the name in the text, which prints the wrong label.
Key takeaways
- A missing key gives the zero value of the value type:
0,""orfalse. - When that is the default you want, a plain
m[key]is enough, and it doesn't add the key. - For another default, or to tell a missing key from a stored zero, use the comma-ok form.
