One of the surprising things beginners realize about Go is that maps are passed by reference. This means if a map is modified in the function it was passed to, the caller will also see the changes.
package main
import "fmt"
func f(m map[int]int) {
m[0] = 1
}
func main() {
m := make(map[int]int)
m[0] = 0
fmt.Println(m) // prints map[0:0]
f(m)
fmt.Println(m) // prints map[0:1]
}
However, if m is a map[int]node, m[0] is not a reference to a node but the value stored in memory. This means you can’t modify the fields of m[0] directly, as m[0] is just a copy of the value.
package main
type node struct {
val int
}
func main() {
m := make(map[int]node)
m[0] = node{val: 1}
m[0].val = 2
}
stderr-> cannot assign to struct field m[0].val in map
To resolve this, you need to first assign map[key] to a variable, modify it, and then put it back into the map. In the code below, since m0 is not reassigned to m, m[0].val remains unchanged.
package main
import "fmt"
type node struct {
val int
}
func main() {
m := make(map[int]node)
m[0] = node{val: 0}
m[1] = node{val: 1}
fmt.Println(m) // prints map[0:{0} 1:{1}]
m0 := m[0]
m0.val = 2
m1 := m[1]
m1.val = 3
m[1] = m1
fmt.Println(m) // prints map[0:{0} 1:{3}]
}
There is a Go proposal from to allow developers to be able to modify map elements directly, however it is still in progress.
More:
1. Why it matters that map values are unaddressable in Go
2. Go maps in action