Go Gopher How to Go

Maps are Go's built-in associative data type, also known as hash tables or dictionaries in other languages. Maps store key-value pairs.

💡 Key Points

  • Maps must be initialized with make or a literal before use
  • Accessing a non-existent key returns the zero value of the value type
  • Use the comma-ok idiom to distinguish between zero values and missing keys
  • Map iteration order is randomized for security reasons
  • Maps are reference types - passing a map doesn't copy its contents
  • Maps are not safe for concurrent use without synchronization
  • Key types must be comparable - slices, maps, and functions cannot be keys

Creating and Using Maps

Maps must be initialized before use with make or a map literal:

package main

import "fmt"

func main() {
    // Create a map with make
    m := make(map[string]int)

    // Set key-value pairs
    m["k1"] = 7
    m["k2"] = 13

    fmt.Println("map:", m)

    // Get a value
    v1 := m["k1"]
    fmt.Println("v1:", v1)

    // len returns number of key-value pairs
    fmt.Println("len:", len(m))

    // Delete a key-value pair
    delete(m, "k2")
    fmt.Println("map:", m)
}
Output:
map: map[k1:7 k2:13]
v1: 7
len: 2
map: map[k1:7]

Checking Key Existence

The optional second return value indicates if the key was present:

package main

import "fmt"

func main() {
    m := map[string]int{"foo": 1, "bar": 2}
    
    // Check if key exists
    v, exists := m["foo"]
    fmt.Println("foo exists:", exists, "value:", v)
    
    v, exists = m["baz"]
    fmt.Println("baz exists:", exists, "value:", v)
    
    // Common idiom
    if val, ok := m["foo"]; ok {
        fmt.Println("Found:", val)
    }
}
Output:
foo exists: true value: 1
baz exists: false value: 0
Found: 1

Map Literals

You can declare and initialize a map in one line:

package main

import "fmt"

func main() {
    // Initialize with values
    n := map[string]int{
        "foo": 1,
        "bar": 2,
    }
    fmt.Println("map:", n)
    
    // Empty map literal
    empty := map[string]int{}
    fmt.Println("empty:", empty)
}
Output:
map: map[bar:2 foo:1]
empty: map[]

Iterating Over Maps

Use range to iterate over key-value pairs:

package main

import "fmt"

func main() {
    m := map[string]string{
        "a": "alpha",
        "b": "beta",
    }
    
    // Iterate over key-value pairs
    for k, v := range m {
        fmt.Printf("%s -> %s\n", k, v)
    }
    
    // Iterate over keys only
    for k := range m {
        fmt.Println("key:", k)
    }
}
Output:
a -> alpha
b -> beta
key: a
key: b

Map Declaration Patterns

PatternExampleDescription
make(map[K]V)make(map[string]int)Create empty map
make(map[K]V, size)make(map[string]int, 10)Create map with initial capacity hint
map[K]V{}map[string]int{}Empty map literal
map[K]V{k:v, ...}map[string]int{"a":1, "b":2}Map literal with initial values
var m map[K]Vvar m map[string]intDeclare nil map (must init before use)

Map Operations

OperationSyntaxExampleDescription
Set valuem[key] = valuem["x"] = 10Add or update key-value pair
Get valuev := m[key]v := m["x"]Retrieve value (zero value if not exists)
Check existencev, ok := m[key]v, ok := m["x"]Get value and existence check
Deletedelete(m, key)delete(m, "x")Remove key-value pair
Lengthlen(m)len(m)Number of key-value pairs
Iteratefor k, v := range mfor k, v := range mLoop through all pairs
Clear (Go 1.21+)clear(m)clear(m)Remove all key-value pairs

Map Key Types

CategoryTypesNotes
Comparable typesbool, int, float, string, pointer, channel, interface, arrayCan be used as map keys
Non-comparableslice, map, functionCannot be used as map keys
Struct keysStructs with comparable fieldsMust have all comparable fields
Array keysArrays with comparable elementsSize is part of type

Map Characteristics

FeatureBehaviorNotes
OrderUnorderedIteration order is random
Reference typePassed by referenceModifications visible to caller
Zero valuenilNil maps cannot be written to
Thread safetyNot safeUse sync.Map or mutex for concurrency
Missing keysReturn zero valueUse comma-ok idiom to check
DeletionSafe during iterationCan delete while ranging

Common Patterns

PatternCodeUse Case
Set data structuremap[T]bool or map[T]struct{}Check membership efficiently
Count occurrencescounts[item]++; // works even if key doesn't existFrequency counting
Group by keymap[K][]VGroup values by category
Check and setif _, ok := m[k]; !ok { m[k] = v }Set only if key doesn't exist
Default valueif v, ok := m[k]; ok { return v } else { return defaultVal }Get with fallback
Nested mapsmap[K1]map[K2]VMulti-level lookup