Golang Pass Map Type Parameter
Observation
When I read this blog section “But maps and channels are references, right?”, I realize that the following code should print true, because Golang pass the map by value, not map address.
package main
import "fmt"
func fn(m map[int]int) {
m = make(map[int]int)
}
func main() {
var m map[int]int
fn(m)
fmt.Println(m == nil)
}
Analysis
This is running result. When the program starts run main function, the active stack frame in memory belongs to main. The m’s memory is 0xc00000e028. When program calls func fn(m map[int]int)
, the program push stack and switch to fn frame as an active frame. When pushing the stack, the parameter m’s value is copied from main, which is nil. It copies value from memory 0xc00000e02 to memory 0xc00000e038. After func fn
returns, the m is the one which is not initialized. Here is the example.
However, when we pass the address of m to the func fn
, the result is false. Here is the example.
package main
import "fmt"
func fn(m *map[int]int) {
fmt.Printf("%p\n", m)
*m = make(map[int]int)
}
func main() {
var m map[int]int
fmt.Printf("%p\n", &m)
fn(&m)
fmt.Println(m == nil)
}
This is because when pushing the stack, the parameter is copy of the address of the m defined in func main
. The map initialization is for the same object at the same memory location.
Caveats
Golang has three data type categories: build-in type like string
or bool
, reference type like slice/array
or map
, and composite type like struct
. It is highly recommended to use value semantic for the build-in type and reference type. Therefore, for this post, *map
is rarely used, even though it works.
For the value semantics convention, any mutation happened inside function should return a new data to the caller.
Conclusion
Many documents have mentioned that, Golang only pass the parameters by value, not reference. My understanding is that, the behavior is the same as C/C++. The function is running in a certain stack frame, all local variables, including the copied the parameters, will be gone after function returned. However, all variables referenced by pointer can be manipulated by the function and mutated accordingly.