Pointers
Like C, go uses pointers. A pointer is used to refer to the address in memory of a variable. You can then use the pointer to refer back to the variable.
package main
import (
"fmt"
)
func main() {
x := 1
p := &x
fmt.Println(p) // prints the address
fmt.Println(*p) // prints the value of what's at that address (1)
*p = 2 // updates x via the pointer
fmt.Println(x)
}
/*
Prints the following:
0xc0000b2008
1
2
*/
The &
operator returns a variable’s address, a pointer to the variable.
The *
operator is used on a pointer to return the value at that address. This is called dereferencing.
The value of a variable that is a pointer is a memory address, something like 0xc0000b2008
.
It’s quite common to pass around pointers as arguments to functions, and use this as a method for aggregating values between functions.
If you want a function to mutate a variable, then you write it to accept a pointer type. For example.
// double the value of an integer
func double(i *int) {
*i += *i
}
TLDR
When you see &
in front of a variable, read it as “address of”.
When you see *
in front of a variable read it as “value at address”.
But when to use pointers?
This video from anthony gg states it quite well, the practical “when would I actually use this” point of view about go pointers. In short, these are the only two times when you really need to use pointers:
- When you want a function to update the value in place rather than copying + updating a value. AKA, a function that mutates a value.
- When you have a lot of functions that use the same value/instance of a struct, and the struct is really big. For example, a struct that has an embedded file as one of the members. In that case, you don’t want to be copying the value over and over again in memory, too expensive. You can use a pointer to save memory + perf.