A map in Go is an unordered collection of key/value pairs, written
map[K]V. It gives you fast lookup by key — the same idea as a dictionary
in Python or an object in JavaScript, but statically typed.
Creating a map
You can build a map from a literal or start empty with the make built-in.
Both give you a ready-to-use map; the keys must be a comparable type such as a
string, an integer, or a bool.
// A map literal with two entries.
ages := map[string]int{
"Ada": 36,
"Alan": 41,
}
// An empty map ready for writes, created with make.
scores := make(map[string]int)
Reading and writing values
You write with m[key] = value and read with m[key]. A key that is not
present does not cause an error: reading it returns the zero value of the
value type.
scores["Ada"] = 100 // write
top := scores["Ada"] // read: 100
missing := scores["Bob"] // absent key: zero value, 0
The comma-ok idiom
Because a missing key returns a zero value, scores["Bob"] == 0 cannot tell
you whether Bob scored zero or is simply absent. The two-value form of the read
solves this: the second value is a bool that is true only when the key
exists.
if score, ok := scores["Bob"]; ok {
fmt.Println("found:", score)
} else {
fmt.Println("Bob has no score yet")
}
Deleting keys and counting with len
delete removes a key (and does nothing if the key is absent). len returns
the number of entries.
delete(scores, "Ada") // remove a key
count := len(scores) // number of entries left
Ranging over a map
A for ... range loop visits every key/value pair. The order is
deliberately randomised by the runtime, so never rely on it. If you need a
stable order, collect the keys into a slice and sort them.
for name, score := range scores {
fmt.Printf("%s -> %d\n", name, score)
}
A complete example
The program below counts how often each word appears in a sentence. It sorts the keys before printing so the output is deterministic. It compiles and runs as-is.
package main
import (
"fmt"
"sort"
"strings"
)
func main() {
text := "the quick brown fox the lazy dog the end the fox"
counts := make(map[string]int)
for _, word := range strings.Fields(text) {
counts[word]++
}
// Collect the keys and sort them so the output is stable,
// because ranging over a map visits keys in random order.
words := make([]string, 0, len(counts))
for word := range counts {
words = append(words, word)
}
sort.Strings(words)
for _, word := range words {
fmt.Printf("%s: %d\n", word, counts[word])
}
}
Running it prints:
brown: 1
dog: 1
end: 1
fox: 2
lazy: 1
quick: 1
the: 4
Maps are reference types
A map value is a small header that points to the underlying data. When you pass a map to a function, both sides share the same storage, so writes made inside the function are visible to the caller. That is powerful, but it has two consequences to keep in mind.
Common mistakes
- Writing to a nil map. Declaring
var m map[string]intgives you a nil map. You mustmakeit before the first write. - Trusting range order. The iteration order changes on every run by design. Sort the keys when you need reproducible output.
- Confusing absent with zero. Use the comma-ok form instead of comparing the value to its zero value.
- Taking a field’s address.
&m[key]is not allowed, because the runtime may move entries. Store a value, modify it, then write it back.
Practice
Given a slice of vote strings, build a map of counts, then use the comma-ok
idiom to report the count for "go", printing go: 0 if it never appeared.
Show the solution
package main
import "fmt"
func main() {
votes := []string{"go", "rust", "go", "python", "go"}
counts := make(map[string]int)
for _, v := range votes {
counts[v]++
}
if n, ok := counts["go"]; ok {
fmt.Printf("go: %d\n", n)
} else {
fmt.Println("go: 0")
}
}Each pass of the loop increments the counter for the current vote. The comma-ok
read then distinguishes a real count from an absent key. Here it prints
go: 3.
Summary
- Create maps with a literal or
make; keys must be comparable. - A missing key reads as the zero value; use the comma-ok form to be sure.
deleteremoves a key,lencounts entries, andrangeorder is random.- Maps are reference types and are not safe for concurrent writes.
Next, learn how to model richer data with structs and methods in Go. If you want to revisit ordered collections first, review arrays and slices.