Overriding pointers inside of local function works as it should… but not the way you might expect!

Intro to pointers

With Go, we can pass variables to functions either by value, and thus any updates to those are not affecting the out of scope variables; or pass by pointer - in which case any updates that are done to the value of that variable will persist after the function call is done.

An example:

package main

import "fmt"

func editValue(x int) {
	x = 100
	fmt.Printf("from inside edit value: %d\n", x)
}

func editPointer(x *int) {
	*x = 101
	fmt.Printf("from inside edit pointer: %d\n", *x)
}

func main() {
	x := 99
	fmt.Printf("from main: %d\n", x)
	editValue(x)
	fmt.Printf("from main after edit value: %d\n", x)
	editPointer(&x)
	fmt.Printf("from main after edit editPointer: %d\n", x)
}

Output:

from main: 99
from inside edit value: 100
from main after edit value: 99
from inside edit pointer: 101
from main after edit editPointer: 101

The gotcha!

However, notice that when editing the value of the pointer - the expression used is *x = <new-value>; and the mistake that I did was miss the *.

The resulting code looked something like:


func editPointer(x *int) {
  y := 101
  x = &y
  fmt.Printf("from inside edit pointer: %d\n", *x)
}

However, what that will do is override the value of x, but only in the local scope!

This means that once we are out of the function x is pointing to the old value. This kind of error can be more easily spotted when using simple types as one cannot use &101 to have a pointer point to the simple value of 101.

When using more complex structs, it’s quite common to create a new struct and assign that to the pointer. This can create some very subtle bugs, especially if the code is not altering all the values in the struct.

A Go playground which showcases this specific issue: link.