Golang map and map literal: basics, global maps, and iteration

Golang map and maps in golang: map[K]V, golang map literal and make, nil map panic, comma-ok lookup, delete and range, ordered iteration via sorted keys, golang global map and concurrency, dictionary analogy to Python.

Published

Updated

Read time 4 min read

Reviewed byDeepak Prasad

Golang map and map literal: basics, global maps, and iteration

A map in Go (golang map, golang maps, map golang, maps golang, map in go) is a built-in hash table: keys are unique, values can repeat, and lookups are fast on average. If you know associative containers as a Python dictionary or a “hash map” in other languages, the same mental model applies—often people also say golang dictionary when searching. This page covers the golang map literal, make, the comma-ok idiom, delete, for range, stable ordering tricks, and what people mean by golang global map (package-level variables and concurrency). For structured records with fixed fields, compare with structs.

Tested with Go 1.24 on Linux.


Map type: map[K]V and comparable keys

The type form is map[KeyType]ValueType. KeyType must be comparable (for example string, int, or pointers); ValueType can be almost anything, including slices, structs, or another map.

Keys must be unique. If you repeat the same key in one literal, the compiler rejects it (duplicate key … in map literal).

The zero value of a map is nil. Reading from nil is safe (you get the value type’s zero value and ok == false in the comma-ok form), but assigning to a nil map panics:

go
package main

import "fmt"

func main() {
	var m map[string]int
	fmt.Println(m, m == nil)
	// m["k"] = 1 // panic: assignment to entry in nil map
}
text
map[] true

Initialize before writing with a golang map literal or make:

go
package main

import "fmt"

func main() {
	lit := map[string]int{"ada": 1, "bob": 2}
	fmt.Println("literal:", lit)

	m := make(map[string]int)
	m["ada"] = 1
	fmt.Println("make:", m)
}
text
literal: map[ada:1 bob:2]
make: map[ada:1]

make(map[K]V, hint) accepts an optional capacity hint for preallocating buckets; the map still grows as needed (spec: make).


Reads, writes, delete, and the comma-ok idiom

Indexing m[k] returns the stored value or the value type’s zero if the key is missing—which is ambiguous for types like int where 0 might be real data. Use two return values:

go
package main

import "fmt"

func main() {
	scores := map[string]int{"ada": 42}
	v, ok := scores["ada"]
	fmt.Println(v, ok)
	v2, ok2 := scores["missing"]
	fmt.Println(v2, ok2)
}
text
42 true
0 false

delete(m, key) removes an entry; it is a no-op if the key is absent.

go
package main

import "fmt"

func main() {
	m := map[string]int{"a": 1, "b": 2}
	delete(m, "a")
	fmt.Println(m)
}
text
map[b:2]

for range on maps in golang (unordered iteration)

for k, v := range m visits every pair, but iteration order is randomized and must not be relied on for stability across runs. That is why two runs can print keys in different orders even if the map contents are identical.

To process keys in a fixed order, copy keys to a slice and sort (numeric example):

go
package main

import (
	"fmt"
	"sort"
)

func main() {
	users := map[int]string{100: "John", 23: "Mary", 54: "Paul", 21: "Josh"}
	keys := make([]int, 0, len(users))
	for k := range users {
		keys = append(keys, k)
	}
	sort.Ints(keys)
	for _, k := range keys {
		fmt.Println(k, users[k])
	}
}
text
21 Josh
23 Mary
54 Paul
100 John

golang global map: package-level maps and concurrency

A “global map” usually means a package-level variable, for example:

go
var userIDs = make(map[string]int) // initialized, not nil

That is convenient for registries or caches, but the Go memory model still applies: unsynchronized concurrent writes to an ordinary map are undefined behavior and can crash. Patterns:

  • Guard the map with sync.Mutex or sync.RWMutex when many goroutines read and write.
  • Use sync.Map when you have lots of disjoint keys or frequent loads with rare stores (documented as a niche optimization, not a drop-in for every map).
  • Prefer passing a map down the call stack or storing it in a struct you own so tests can substitute fakes.

For printing map types in debugging, see print variable type.


Standard library maps helpers (Go 1.21+)

The maps package provides utilities such as maps.Clone, maps.Equal, and maps.Copy for common map workflows without reimplementing them by hand.


Summary

Maps in golang give you fast key/value storage with a compact literal syntax and make for empty, ready-to-write tables. Remember the distinction between a nil map (reads ok, writes panic) and an empty-but-initialized map, use the comma-ok form when zero values are ambiguous, and treat for range over a map as intentionally unordered unless you sort keys yourself. A golang global map is just a package-level value: safe only with clear ownership or explicit synchronization. If you outgrow ad-hoc maps for configuration-shaped data, reach for structs or dedicated types.


References


Frequently Asked Questions

1. Is a golang map the same as a Python dictionary?

They are the same idea—a key/value associative table—but Go requires comparable keys, has a nil map distinction, and iteration order is deliberately randomized. See also Python dictionary.

2. Can I use a golang global map from many goroutines?

Not without synchronization. A package-level map[string]T is fine for reads and writes from one goroutine, or protect it with sync.Mutex or sync.RWMutex, or use sync.Map for specialized cache-style workloads.

3. What happens if I write to a nil map?

Assignment panics with assignment to entry in nil map. Call make or use a map literal first.

4. How do I tell a missing key from a zero value?

Use the two-value form value, ok := m[key]; ok is false when the key is absent.
Antony Shikubu

Systems Integration Engineer

Highly skilled software developer with expertise in Python, Golang, and AWS cloud services.