Map operations: comma-ok and delete
"Missing key" and "present with the zero value" look identical through a plain lookup. That works for some patterns (counting word frequencies, accumulating into a running total), but it breaks down the moment the zero value is a legitimate stored value: a map of shopping-cart quantities where 0 means "explicitly cleared", a map of feature flags where false means "explicitly turned off". This lesson covers the two operations that handle "missing versus present" cleanly: the comma-ok form for reading, and delete for removal.
Comma-ok: telling missing from zero
Map reads have two forms. The single-value form you have seen returns only the value:
ages := map[string]int{"alice": 30}
fmt.Println(ages["alice"]) // 30
fmt.Println(ages["nobody"]) // 0 (can't tell: really 0, or missing?)
The comma-ok form adds a second return value: a bool that is true if the key was present and false if it was not:
ages := map[string]int{"alice": 30, "charlie": 0}
if v, ok := ages["alice"]; ok {
fmt.Println("alice is", v)
} else {
fmt.Println("no alice")
}
if v, ok := ages["charlie"]; ok {
fmt.Println("charlie is", v)
} else {
fmt.Println("no charlie")
}
if v, ok := ages["nobody"]; ok {
fmt.Println("nobody is", v)
} else {
fmt.Println("no nobody")
}
Output:
alice is 30
charlie is 0
no nobody
charlie exists with value 0; nobody does not exist at all. Without ok, both reads would give you 0 and you could not tell them apart. With ok, you always can.
The short-statement if form from Chapter 2 (if v, ok := m[k]; ok { ... }) is the pattern this feature exists for. You will write it dozens of times in real Go code.
delete removes a key
delete(m, k) removes the entry for key k from map m. It returns nothing. Deleting a key that is not present is a no-op, not an error:
m := map[string]int{"a": 1, "b": 2, "c": 3}
delete(m, "b")
fmt.Println(m) // map[a:1 c:3]
delete(m, "nobody") // no-op, no error
fmt.Println(m) // map[a:1 c:3]
After delete, reading the deleted key returns the zero value (just like any other missing key), and a comma-ok read returns false for the ok result.
len counts the entries
len(m) returns the number of key-value pairs in the map:
m := map[string]int{"a": 1, "b": 2}
fmt.Println(len(m)) // 2
m["c"] = 3
fmt.Println(len(m)) // 3
delete(m, "a")
fmt.Println(len(m)) // 2
len(nil) on a map is 0, so if len(m) == 0 { ... } works whether the map is nil or merely empty, without any special-case branch.
Starter declares inventory := map[string]int{"apple": 3, "banana": 0, "cherry": 12}. The "banana" entry is legitimately zero (we have zero bananas in stock), not missing.
- Use the comma-ok form to look up
inventory["banana"]. If the key is present, print"banana in stock: <count>". If not, print"banana not tracked". - Use the comma-ok form again for
inventory["durian"]. Print"durian in stock: <count>"if present,"durian not tracked"if not. - Delete
"apple"from the map. - Print
len(inventory)on its own line.
Expected output:
banana in stock: 0
durian not tracked
2
banana in stock: 0 durian not tracked 2