Skip to main content

Introduction

Maps are Go’s built-in associative data type (sometimes called hashes or dicts in other languages). They store key-value pairs and provide fast lookups, inserts, and deletes based on keys.

The Code

// _Maps_ are Go's built-in [associative data type](https://en.wikipedia.org/wiki/Associative_array)
// (sometimes called _hashes_ or _dicts_ in other languages).

package main

import (
	"fmt"
	"maps"
)

func main() {

	// To create an empty map, use the builtin `make`:
	// `make(map[key-type]val-type)`.
	m := make(map[string]int)

	// Set key/value pairs using typical `name[key] = val`
	// syntax.
	m["k1"] = 7
	m["k2"] = 13

	// Printing a map with e.g. `fmt.Println` will show all of
	// its key/value pairs.
	fmt.Println("map:", m)

	// Get a value for a key with `name[key]`.
	v1 := m["k1"]
	fmt.Println("v1:", v1)

	// If the key doesn't exist, the
	// [zero value](https://go.dev/ref/spec#The_zero_value) of the
	// value type is returned.
	v3 := m["k3"]
	fmt.Println("v3:", v3)

	// The builtin `len` returns the number of key/value
	// pairs when called on a map.
	fmt.Println("len:", len(m))

	// The builtin `delete` removes key/value pairs from
	// a map.
	delete(m, "k2")
	fmt.Println("map:", m)

	// To remove *all* key/value pairs from a map, use
	// the `clear` builtin.
	clear(m)
	fmt.Println("map:", m)

	// The optional second return value when getting a
	// value from a map indicates if the key was present
	// in the map. This can be used to disambiguate
	// between missing keys and keys with zero values
	// like `0` or `""`. Here we didn't need the value
	// itself, so we ignored it with the _blank identifier_
	// `_`.
	_, prs := m["k2"]
	fmt.Println("prs:", prs)

	// You can also declare and initialize a new map in
	// the same line with this syntax.
	n := map[string]int{"foo": 1, "bar": 2}
	fmt.Println("map:", n)

	// The `maps` package contains a number of useful
	// utility functions for maps.
	n2 := map[string]int{"foo": 1, "bar": 2}
	if maps.Equal(n, n2) {
		fmt.Println("n == n2")
	}
}

Map Fundamentals

Creating Maps

m := make(map[string]int)
Use make to create an empty map. The syntax is make(map[key-type]value-type). This creates a map with string keys and int values.
An uninitialized map (var m map[string]int) is nil and will panic if you try to write to it. Always initialize maps with make or a map literal.

Setting Values

m["k1"] = 7
m["k2"] = 13
Set key/value pairs using square bracket notation. If the key already exists, its value is updated.

Getting Values

v1 := m["k1"]
fmt.Println("v1:", v1)  // v1: 7
Retrieve values using the key. If the key doesn’t exist, you get the zero value for the value type:
v3 := m["k3"]  // k3 doesn't exist
fmt.Println("v3:", v3)  // v3: 0 (zero value for int)

Map Operations

Checking Key Existence

_, prs := m["k2"]
fmt.Println("prs:", prs)  // false if key doesn't exist
The “comma ok” idiom uses a second return value to check if a key exists:
  • First value: the value (or zero value if key doesn’t exist)
  • Second value: true if key exists, false otherwise
Use the comma ok idiom to distinguish between a missing key and a key with a zero value: value, exists := m[key]

Map Length

fmt.Println("len:", len(m))  // Number of key/value pairs
The len function returns the number of key/value pairs in the map.

Deleting Keys

delete(m, "k2")
The delete builtin removes a key/value pair from a map. It’s safe to delete a key that doesn’t exist (no-op).

Clearing All Keys

clear(m)
The clear builtin (Go 1.21+) removes all key/value pairs from a map, leaving it empty.

Map Initialization

n := map[string]int{"foo": 1, "bar": 2}
Declare and initialize a map in one line using a map literal. This is more concise than make when you know the initial values.
// Empty map literal
m := map[string]int{}

// With initial values
m := map[string]int{
    "alice": 25,
    "bob":   30,
    "carol": 28,
}

The Maps Package

import "maps"

n2 := map[string]int{"foo": 1, "bar": 2}
if maps.Equal(n, n2) {
	fmt.Println("n == n2")
}
The maps package (Go 1.21+) provides useful utilities:
  • maps.Equal(): Compare two maps
  • maps.Clone(): Create a shallow copy
  • maps.Copy(): Copy entries from one map to another
  • And more…
You cannot compare maps directly with == (except to nil). Use maps.Equal() from the maps package.

Map Characteristics

Unordered

Maps are unordered - iteration order is not guaranteed and may vary between runs.

Reference Type

Maps are reference types. When you pass a map to a function, both the function and caller refer to the same underlying data.
func modify(m map[string]int) {
    m["key"] = 100  // Modifies the original map
}

Valid Key Types

Key types must be comparable (support == and !=):
  • ✅ Strings, integers, floats, booleans, pointers, channels, arrays
  • ❌ Slices, maps, functions

Common Patterns

Checking and Setting

if _, exists := m[key]; !exists {
    m[key] = defaultValue
}

Iterating Over Maps

for key, value := range m {
    fmt.Printf("%s: %d\n", key, value)
}

Map of Slices

m := make(map[string][]int)
m["key"] = append(m["key"], 1, 2, 3)

Counting Occurrences

counts := make(map[string]int)
for _, item := range items {
    counts[item]++  // Zero value (0) works perfectly
}

Zero Value Behavior

Go’s zero values make maps very convenient. For numeric values, you can increment without checking if the key exists: m[key]++ works even if key is new.

Key Takeaways

  • Create maps with make(map[K]V) or map literals map[K]V{}
  • Access values with m[key], set with m[key] = value
  • Use comma ok idiom value, exists := m[key] to check existence
  • Missing keys return the zero value for the value type
  • Delete keys with delete(m, key)
  • Clear all entries with clear(m) (Go 1.21+)
  • Maps are unordered - don’t rely on iteration order
  • Maps are reference types - passed by reference to functions
  • Use the maps package for utilities like Equal() and Clone()
  • Only comparable types can be map keys (no slices, maps, or functions)

Build docs developers (and LLMs) love