A map is a collection of key-value pairs. Instead of looking up by index (like in a slice), you look up by a key — a username, a country code, a product ID.
If you’ve used Python’s dict, JavaScript’s Object, or Java’s HashMap, this is the same idea.
Creating a map
package main
import "fmt"
func main() {
capitals := map[string]string{
"India": "New Delhi",
"France": "Paris",
"Japan": "Tokyo",
"Brazil": "Brasília",
}
fmt.Println(capitals)
fmt.Println("Capital of India:", capitals["India"])
}
map[Brazil:Brasília France:Paris India:New Delhi Japan:Tokyo]
Capital of India: New Delhi
Reading the type map[string]string:
map— this is a map[string]— keys are stringsstring— values are strings
You can have any combination: map[string]int, map[int]string, even nested maps.
Maps are not ordered. The order of keys when you iterate or print a map is intentionally randomized in Go. If you depend on order, use a slice or sort the keys explicitly.
Adding, updating, and reading
// inside main()
capitals := map[string]string{
"India": "New Delhi",
"France": "Paris",
}
capitals["Japan"] = "Tokyo" // add new key
capitals["France"] = "PARIS" // update existing key
city := capitals["India"] // read
fmt.Println(city)
Adding and updating use the same syntax — Go figures out which is happening based on whether the key already exists.
The “comma ok” idiom
What happens if you read a key that doesn’t exist?
// inside main()
capitals := map[string]string{"India": "New Delhi"}
city := capitals["Mars"]
fmt.Println(city)
fmt.Println(len(city))
0
It returned the zero value of the value type — for strings, that’s "". No error, no crash. This is convenient sometimes, but dangerous if you can’t tell “missing key” from “key with empty value.”
The fix is the “comma ok” idiom — Go returns two values when you read from a map:
// inside main()
capitals := map[string]string{"India": "New Delhi"}
if city, ok := capitals["Mars"]; ok {
fmt.Println("Capital:", city)
} else {
fmt.Println("Mars not in map")
}
Mars not in map
The second return value (ok) is a bool — true if the key was present, false if not. This is the canonical way to check for a key in Go. Use it whenever the difference matters.
Deleting
Use the built-in delete function:
// inside main()
capitals := map[string]string{
"India": "New Delhi",
"France": "Paris",
}
delete(capitals, "France")
fmt.Println(capitals)
map[India:New Delhi]
If the key doesn’t exist, delete does nothing. No error.
Iterating
Use range — same as with slices, but you get key and value instead of index and value:
// inside main()
capitals := map[string]string{
"India": "New Delhi",
"France": "Paris",
"Japan": "Tokyo",
}
for country, city := range capitals {
fmt.Println(country, "->", city)
}
Japan -> Tokyo
India -> New Delhi
France -> Paris
(The order will be different every time you run it. That’s a feature, not a bug — it stops you from accidentally writing code that depends on an order Go doesn’t promise.)
Creating an empty map
Two ways to create a map you’ll fill in later:
// inside main()
votes := make(map[string]int) // works — ready to use
votes["yes"]++ // 1
votes["no"]++ // 1
votes["yes"]++ // 2
fmt.Println(votes)
map[no:1 yes:2]
A map declared with just
var m map[string]intisnil— you can read from it (returning zero values) but writing crashes the program. Always usemakeor a literal{}.
A practical example
A word-count program. Read a sentence, count how often each word appears:
package main
import (
"fmt"
"strings"
)
func main() {
text := "the quick brown fox jumps over the lazy dog the fox is quick"
counts := make(map[string]int)
for _, word := range strings.Fields(text) {
counts[word]++
}
for word, count := range counts {
fmt.Println(word, ":", count)
}
}
the : 3
quick : 2
brown : 1
fox : 2
jumps : 1
over : 1
lazy : 1
dog : 1
is : 1
strings.Fields splits a string by whitespace. The counts[word]++ line is the magic: if word isn’t in the map, counts[word] returns 0 (the zero value for int), then ++ makes it 1 and stores it. If it’s already there, ++ increments it. No special-casing needed.
Word counting in fewer than 15 lines is the kind of thing that makes Go pleasant to write.
What’s next
You can store ordered lists (slices) and key-value pairs (maps). Real programs also need structured records — a customer with a name, email, and address held together. That’s what structs are for, and we’ll learn them alongside pointers in the next lesson.