Learn Go Pointer and Difference with Passing by Reference

Everything is Passing by Value

In Go’s design, all values are simply “Passing by value”:

func updateName(newName string){
newName = "bar"
}
func main() {
name := "foo"
updateName(name)
fmt.Println(name) // foo
}

Go will create a copy of the variable’s value into a new local variable newName. Modifications to newName will not affect the external name, because they are already different variables.

Values Wrapped by Pointer

func updateName(data map[string]string) {
data["name"] = "bar"
}
func main() {
data := map[string]string{
"name": "foo",
}
updateName(data)
fmt.Println(data["name"]) // bar
}

However, when dealing with some types of values like Slices, Maps, and Functions, you may encounter behaviors like “Passing by reference”. In reality, this is because although values are being passed, they are actually “Pointers” pointing to another memory location.

You can obtain the memory address of a variable using &, and get the value at that memory address using *:

name := "foo"
namePointer := &name
fmt.Println(&name) // 0x14000122020
fmt.Println(*namePointer) // foo

Returning to the previous example, by passing a Pointer instead of a value, you can accomplish creating and modifying name under the “Passing by value” pattern:

func updateName(newName *string){
*newName = "bar"
}
func main() {
name := "foo"
updateName(&name)
fmt.Println(name) // bar
}

Summary

Value Types (Pure Value Types)Reference Types (Value Types with Pointers)
StringsSlices
IntsMaps
FloatsFunctions
Booleans
Arrays
Structs
  • Everything in Go is Passing by Value
  • Reference Types have pointers and copy pointers during copying
  • To get Value Types to behave like Passing by Reference, you must explicitly use Pointers

Passing by Reference is a feature in other languages like C++ or C#, equivalent to the compiler directly binding “the variable itself” to the function parameters without the need to manipulate Pointers.

Further Reading