"The bugs you don't understand are the ones that teach you the most."


1. Maps & Channels Are Reference Types

Like slices, maps and channels contain internal pointers:

func modifyMap(m map[string]int) {
    m["key"] = 100  // ✓ Caller sees it
}

func sendData(ch chan int) {
    ch <- 42  // ✓ Works
}

func main() {
    m := make(map[string]int)
    modifyMap(m)
    fmt.Println(m["key"])  // 100

    ch := make(chan int)
    go sendData(ch)
    fmt.Println(<-ch)  // 42
}

But: Reassigning the map/channel itself requires a pointer.


2. Method Receivers: Pointer vs Value

type Counter struct {
    count int
}

// Value receiver — copies struct
func (c Counter) IncrementWrong() {
    c.count++  // ❌ Modifies copy
}

// Pointer receiver — modifies original
func (c *Counter) IncrementRight() {
    c.count++  // ✓ Modifies original
}

func main() {
    c := Counter{count: 0}
    
    c.IncrementWrong()
    fmt.Println(c.count)  // 0
    
    c.IncrementRight()
    fmt.Println(c.count)  // 1
}

Guidelines:


3. Can't Take Address of Map Elements

m := map[string]int{"a": 1}

ptr := &m["a"]  // ❌ Compile error!

Why? Maps relocate elements during growth, invalidating pointers.

Workaround: Store pointers in the map:

type Data struct { value int }

m := map[string]*Data{
    "a": {value: 1},
}

m["a"].value = 100  // ✓ Works