DEV Community

Cover image for 🗺️ Go Maps Deep Dive — Part 0: Understanding the Basics
arshia_rgh
arshia_rgh

Posted on

🗺️ Go Maps Deep Dive — Part 0: Understanding the Basics

Series Intro:

Welcome to the start of my Go maps deep-dive series!
In the upcoming parts, we’ll go from the outer layer of maps to their deep internals — how they’re implemented under the hood, memory layout, hash functions, optimizations, and performance tricks.
This is Part 0, where we’ll start from the basics: what maps are, how they behave, and what you should know before diving deeper.

🧩 What Are Maps?

In Go, a map is a key-value data structure.
If you’ve used Rust, you know it as a HashMap.
If you’ve used Python, you know it as a dict.

m := map[string]int{
    "apple":  5,
    "orange": 3,
}
fmt.Println(m["apple"]) // 5

Enter fullscreen mode Exit fullscreen mode

They’re unordered collections of key-value pairs, designed for fast lookups and inserts.

🗝️ Maps Are Pointers

Unlike slices, maps in Go are internally pointers to a data structure called hmap.
This has two important consequences:

  • You don’t need to pass them by pointer.
  • When you pass a map to a function, you’re already passing a pointer under the hood. ( in old versions you were used to do like *map[int]int but changed) see Lan Taylor

In the very early days what we call maps now were written as pointers, so you wrote *map[int]int. We moved away from that when we realized that no one ever wrote map without writing *map.

The zero value is nil.

var m map[string]int
fmt.Println(m == nil) // true
Enter fullscreen mode Exit fullscreen mode
  • if you declare a map and then assign it to the new value the both m1, and m2 will be placed in unique memory locations (see blog by dave chenny There is no pass-by-reference in Go) and them value both will be the address of a same hmap structure.
  • Actually the m1 will be cpoied to the m2 (like all assigns in Golang)
  • Updating m2 also updates m1.
m1 := make(map[string]int)
m2 := m1
Enter fullscreen mode Exit fullscreen mode

Go map pointer diagram
Diagram: m1 and m2 point to the same underlying hmap struct ( picture by VictoriaMetrics )

⚖️ Maps Are Not Comparable

Unlike slices, you cannot compare two maps directly:

m1 := map[string]int{}
m2 := map[string]int{}

// This will not compile ❌
if m1 == m2 {}

// This will not compile too ❌
if m1 == m1 {}

// But you *can* check if a map is nil ✅
if m1 == nil {
    fmt.Println("m1 is nil")
}

Enter fullscreen mode Exit fullscreen mode

🔑 Keys Must Be Comparable

The type you use as a key must be comparable in Go.

✅ Valid keys:

  • string
  • int, float64
  • struct (if all fields are comparable)

❌ Invalid keys:

  • slice
  • map
  • function

interface{} or any can be sometimes ok sometimes nok:

var x, x2 map[interface{}]int

x["a"] = 1 // OK✅

x2[[]int{1, 2}] = 1 //runtime panic!❌
Enter fullscreen mode Exit fullscreen mode

⏱️ Lookup and Insert Are Usually O(1)

Go maps are hash-based, so operations like searching and inserting are on average O(1):

Why “usually” O(1)?
In upcoming parts, we’ll explore hash collisions, buckets, and why performance can sometimes degrade. Stay tuned! 👀

⚡ Maps Are Not Thread-Safe

Go maps are not safe for concurrent writes.
If you try, you’ll get a fatal runtime error:

m := map[int]int{}
go func() { m[1] = 42 }()
go func() { m[2] = 84 }()
Enter fullscreen mode Exit fullscreen mode

💥 Runtime panic: concurrent map writes

🏗️ Creating Maps with make

You can create maps with make:

m := make(map[int]int, 10)
Enter fullscreen mode Exit fullscreen mode

Here, the 10 is not the length — it’s a hint to Go about the expected size.
This helps reduce resizing overhead when inserting many items.

We’ll talk about why it’s just a hint and how Go actually allocates buckets in a future part.

🔜 What’s Next?

This is just the beginning! In Part 1, we’ll start peeling back the layers of the hmap structure — the backbone of Go maps.
We’ll cover:

  • The internal hmap struct
  • Buckets and hashing
  • Load factors and resizing strategies

and after all parts you will have good sight about what happening exactly inside the go internals for maps

Stay tuned — things are about to get really interesting! 🚀

Top comments (0)