Maps
A map associates keys with values. Create one with make or a map literal:
package main
import "fmt"
func main() {
ages := make(map[string]int)
ages["alice"] = 30
ages["bob"] = 25
ports := map[string]int{"http": 80, "https": 443}
fmt.Println(ages["alice"], ports["https"]) // 30 443
fmt.Println(len(ages)) // 2
}
map[string]int reads as "map from string to int". Assign with
m[key] = value, read with m[key], count entries with len(m).
Missing keys return the zero value
Looking up a key that isn't there doesn't panic or return an error — you get the value type's zero value:
fmt.Println(ports["gopher"]) // 0 — no such key, zero value of int
This is often exactly what you want. A counter, for instance, needs no "does the key exist yet?" dance:
counts := make(map[string]int)
counts["go"]++ // missing key reads as 0, so this stores 1
counts["go"]++ // now 2
The comma-ok idiom
But "zero" and "absent" can be different questions — is Bob aged 0, or is Bob not in the map? A map lookup can return a second result saying whether the key was present:
age, ok := ages["bob"]
if !ok {
fmt.Println("no bob here")
}
This comma-ok idiom is everywhere in Go. And to remove a key entirely:
delete(ages, "bob") // no-op if the key isn't there
Iteration order is randomized — on purpose
for k, v := range m visits every entry, but in no particular order —
and the order genuinely changes between runs. That's not sloppiness; the Go
team deliberately randomizes it. Early Go programs accidentally depended on
one implementation's stable order, which made changing the map internals a
breaking change. Randomizing from day one means no program can ever grow that
dependency: if you need sorted keys, you sort them yourself, explicitly.
for word, n := range counts {
fmt.Println(word, n) // some order today, another tomorrow
}
Maps are references
Unlike arrays, a map value is a small reference to shared internal storage.
Pass a map to a function and the function's writes are visible to the caller
— no copying happens. The zero value of a map is nil: reading from a nil
map is safe (zero values again), but writing to one panics, which is why
you make a map before filling it.
Time to put the counter pattern to work: the exercise asks you to count words
in a string. strings.Fields(s) splits a string into a []string of
whitespace-separated words — combine it with a map counter and you're done.
Practice
1. Word Count
BeginnerImplement
wordCountso it returns how many times each word appears ins:func wordCount(s string) map[string]intA "word" is whatever
strings.Fieldsproduces: the string split on any run of whitespace (spaces, tabs, newlines). Words are case-sensitive —"Go"and"go"are different words.For example,
wordCount("the quick the lazy the")returnsmap[the:3 quick:1 lazy:1], andwordCount(" ")returns an empty map (a non-nil map with no entries).Make the map first, then range over
strings.Fields(s)and increment — remember that a missing key reads as0, socounts[w]++works on the very first occurrence.package main import "fmt" // wordCount returns how many times each whitespace-separated word // appears in s. Words are case-sensitive. func wordCount(s string) map[string]int { // TODO: implement — import "strings" and use strings.Fields(s) return make(map[string]int) } func main() { fmt.Println(wordCount("the quick the lazy the")) }Sign in to write and run your solution in the browser.
Sign in for hints and the solution.