The Comma-Ok Idiom
tally gains a feature: it remembers the line on which each word last appeared, with lines numbered from 0. Now lastLine["go"] returns 0 — but did "go" appear on the first line, or never at all? The zero value that made counting easy has become ambiguous. Go's answer is a second return value.
The rule
Ask for
okwhenever zero could be a real answer.
Any map lookup can return two values:
line, ok := lastLine["go"]lineis the stored value, or the zero value if the key is absent.okistrueif the key is present,falseif not — regardless of what the value is.
lastLine := map[string]int{"tally": 0}
n, ok := lastLine["tally"] // 0 true — present, on line 0
m, ok2 := lastLine["go"] // 0 false — absentThe usual shape puts it in an if header, so the variables live only where they matter:
if line, ok := lastLine[w]; ok {
fmt.Printf("%q last seen on line %d\n", w, line)
} else {
fmt.Printf("%q never appears\n", w)
}If you only care about presence, discard the value: _, seen := lastLine[w].
The same two-value pattern — hence the name "comma ok" — appears in two other places you will meet later:
- Type assertions:
s, ok := v.(string). Withoutok, a wrong type panics; with it, you getok == falseinstead. - Channel receives:
v, ok := <-ch.okis false once the channel is closed and empty.
The shortcut
Before trusting a lookup, ask "could the zero value also be a genuine value?" If yes — a count that can be 0, a line number, a bool flag stored as false — use comma-ok. If zero can only mean "absent", the single-value form is fine.
The ambiguous read
lastLine["go"]is 0. That fits both "line 0" and "missing".
Drills
Answer fast — trust the rule.
m := map[string]int{"a": 0}. What does _, ok := m["a"] give for ok?
m := map[string]int{"a": 0}. What are v, ok := m["b"]?
var x any = 42. What happens with s := x.(string), without ok?
For which map is the single-value lookup m[k] already unambiguous?
Remember
- Ask for
okwhenever zero could be a real answer. - Shortcut: "could zero be genuine?" Yes →
v, ok := m[k]and branch on ok. - Trap: type assertions without ok panic; map lookups without ok just return zero.
