Pointer
In Go a pointer is represented using the * character followed by the type of the stored value.
* is also used to "dereference" pointer variables. Dereferencing a pointer gives us access to the value the pointer points to.
When we write *xPtr = 0 we are saying "store the int 0 in the memory location that xPtr refers to".
- If we try
xPtr = 0instead we will get a compiler error becausexPtris not anintit's a*int, which can only be given another*int.
We use the & operator to find the address of a variable. &x returns a *int (pointer to an int) because x is an int. This is what allows us to modify the original variable. &x in main and xPtr in zero refer to the same memory location.
When we use the & operator in front of a variable c, we are talking about the place where c is stored. When we use the * operator, we are talking about the variable c itself.
We can get the memory address of a variable by prepending it with an &
i := 7
fmt.Println(&i) // 0xc420014090
As expected, the inc function wouldn't cause the value of i to change, since i is copied by value, so x in the inc function is just a copy, which gets incremented, but then is discarded, since the function doesn't return anything.
func main() {
i := 7
inc(i)
fmt.Println(i) // 7
}
func inc(x int) {
x++
}
If we want to modify the value of i here, then we can do so by passing a pointer to the variable to inc. In this case, the inc function receives a value at that memory reference and is able to modify the original version.
func main() {
i := 7
// pass the pointer of `i` to the `inc` function
inc(&i)
fmt.Println(i) // 7
}
// here, we say "the function accepts a pointer that, when dereferenced, is an integer"
func inc(x *int) {
// dereference the pointer before incrementing; otherwise we'd be incrementing the memory address (ie. 0xc420014090).
*x++
}
Use-cases
Pointers give us the ability to define a function that accepts a pointer as an argument so that the original variable can be modified from within the function.
func zero(xPtr *int) {
*xPtr = 0
}
func main() {
x := 5
zero(&x)
fmt.Println(x) // x is 0
}
- this also has the added benefit of not having to copy the value into a local function version on each method call.
Pointers are extremely useful when paired with structs.
Backlinks