Reading a value with square brackets
To read a value from a Go map, put the key in square brackets after the map's name. The expression produces the value stored under that key:
scores := map[string]int{"Alice": 95, "Bob": 87}
aliceScore := scores["Alice"] // 95
bobScore := scores["Bob"] // 87
The key you pass must have the map's key type. For a map[string]int that means a string, and the result has the value type, here int. The lookup goes straight to the entry instead of scanning, so it stays fast however many entries the map holds.
What happens when the key is missing
Go doesn't raise an error for a key that isn't in the map. The lookup gives the zero value of the value type instead: 0 for numbers, "" for strings and false for booleans.
fmt.Println(scores["Zed"]) // 0
A read never adds the key. After the line above, len(scores) is unchanged. Only an assignment creates an entry.
The silent zero has a cost: 0 could be Zed's real score or just a sign that Zed is absent. The two-value form of the lookup settles it by also returning a boolean that is true only when the key exists:
if val, ok := scores["Alice"]; ok {
fmt.Println(val) // 95
}
if _, ok := scores["Zed"]; !ok {
fmt.Println("no Zed")
}
In the if header, val and ok exist only for that statement and its branches. The blank identifier _ throws the value away when you only want to know whether the key is there. Go refuses to compile a variable that is declared and never used, so _ is how you say "I don't need this one".
Using the value you read
A lookup is an ordinary expression, so you can use it wherever a value of that type fits, such as in arithmetic or a comparison:
total := scores["Alice"] + scores["Bob"] // 182
A common pattern is to look up a list of names and handle the missing ones separately:
for _, n := range []string{"Alice", "Bob", "Zed"} {
if s, ok := scores[n]; ok {
fmt.Println(n, s)
} else {
fmt.Println(n, "missing")
}
}
With Alice at 95 and Bob at 87, this prints the first two names with their scores, and then Zed missing. Without the ok check, Zed would appear as a student with a score of 0.
If the map was only declared and never created, a lookup still works: it behaves like a lookup in an empty map. Only writing to such a map fails. So reading is always safe in Go, which is why the check for presence is something you add on purpose rather than something the language forces on you.
The exercise
The editor already holds the scores map with Alice, Bob and Charlie. The single step is to read Alice's score into a new variable named aliceScore. Use :=, which declares the variable and infers its type from the right-hand side, and put scores["Alice"] on the right.
The solution in Go
scores := map[string]int{"Alice": 95, "Bob": 87, "Charlie": 72}
aliceScore := scores["Alice"]
After this line, aliceScore is an int holding 95. It is a copy of the value, so changing aliceScore later does not change the map. Writing aliceScore = 0 leaves scores["Alice"] at 95.
Common mistakes
- Misspelling the key. Keys are compared exactly, so
"alice"is a different key from"Alice". The misspelled lookup quietly gives 0. - Using
=for the first assignment. A new variable needs:=. Plain=only assigns to a variable that already exists. - Treating 0 as "missing". A real score of 0 and an absent key look the same without the second value.
- Wrong key type. A
map[string]intcan't be indexed with a number likescores[1]. That is a compile error, not a missing key.
Key takeaways
m[key]reads a value, and a missing key gives the zero value without an error and without adding the key.val, ok := m[key]tells you whether the key was really present.- The value you read is a copy. Change the map only by assigning to
m[key].