The Proper Use of Pointers in Go (Golang)

Go has become increasingly popular in recent years, especially in my local area. It has been consistently displacing other backend languages like Ruby, Python, C# and Java. Go is wanted for its simplicity, explicitness, speed, and low memory consumption.

Sorry to interrupt! I just wanted to mention that you should check out my new free Go course. It’s designed to teach you all the fundamentals of my favorite coding language.

Many developers that are new to the language, or new to a language that can handle memory directly using pointers end up misusing those pointers.

What Is a Pointer?

A pointer is a variable that stores the address of a value, rather than the value itself. If you think of a computer’s memory (RAM) as a JSON object, a pointer would be like the key, and a normal variable would be the value.

{ "pointer": "variableValue" }
Code language: JSON / JSON with Comments (json)

Lets see one in action:

package main import "fmt" func main() { // create a normal string variable name := "original" // pass in a pointer to the string variable using '&' setName(&name, "qvault") fmt.Println(name) } func setName(ptr *string, newName string) { // dereference the pointer so we can modify the value // and set the value to "qvault" *ptr = newName }
Code language: Go (go)

This prints:

qvault

As you can see, because we have a pointer to the address of the variable, we can modify its value, even within the scope of another function. If the value were not a pointer, this would not work:

package main import "fmt" func main() { name := "original" setNameBroken(name, "qvault") fmt.Println(name) } func setNameBroken(ptr string, newName string) { ptr = newName }
Code language: Go (go)

prints:

original

Pointers can be useful, but in the same way that they are useful, they can be dangerous. For example, if we dereference a pointer that has no value, the program will panic. For this reason we always check if an error value is nil before trying to print it.

Syntax

1. Creating a pointer: &

newString := "" newStringPointer := &newString
Code language: Go (go)

If you print that pointer you will see a memory address.

package main import "fmt" func main() { newString := "" newStringPointer := &newString fmt.Println(newStringPointer) }
Code language: Go (go)

prints: 0xc00000e1e0

Which is the memory address of that variable in your machine.

2. Describing a pointer: *

In a function signature or type definition, the * is used to designate that a value is a pointer.

func passPointer(pointer *string) { }
Code language: Go (go)

3. Dereferencing a pointer: *

It can be slightly confusing, but the * is used to describe a pointer and it is also used as an operator to dereference a pointer.

func derefPointer(pointer *string) { newStringVariable := *pointer // newStringVariable is just a normal string }
Code language: Go (go)

When Should I Use a Pointer?

There are probably many nuanced cases for when a pointer is a good idea, but I would guess that 95% of the time when you use a pointer, it should be for one the following reasons:

1. A function that mutates one of its parameters

When I call a function that takes a pointer as an argument, I expect that my variable will be mutated. If you aren’t mutating the variable in your function, then you probably shouldn’t be using a pointer.

2. Better Performance

If you have a string that contains an entire novel in memory it gets really expensive to copy that variable each time it is passed to a new function. It may be worthwhile to pass a pointer instead, which will save CPU and memory. This comes at the cost of readability however, so only make this optimization if you must.

3. Need a Nil Value Option

Sometimes a function needs to know what something’s value is, as well as if it exists or not. I usually use this when decoding JSON to know if a field exists or not. For example, if a JSON object is:

{ "name": "qvault" } ----> *name: "qvault"
Code language: JavaScript (javascript)
{ "name": "" } ----------> *name: ""
Code language: JavaScript (javascript)
{} ----------------------> *name: nil
Code language: CSS (css)

These are some rules of thumb for when to use pointers in your code. If you are unsure, and a normal value will work just fine, I would advise avoiding the pointer. Pointers are useful tools but can lead to nasty bugs or unreadable code quite easily.

Have questions or feedback?

Follow and hit me up on Twitter @q_vault if you have any questions or comments. If I’ve made a mistake in the article be sure to let me know so I can get it corrected!

Related Reading

2 thoughts on “The Proper Use of Pointers in Go (Golang)”

  1. The performance will not necessarily be a problem, and by the time it will, you probably have other problems:
    Go will pass a reference, even if you don’t use a pointer, as long as there is no risk that the passed variable will be modified.

    So your only risk is that you modify a variable that was not meant to be modified and therefore force Go to use a copy. But then again: what else should happen? If you don’t need to modify it in the first place, then don’t. If you do but don’t want it to taint your inputs, you need a copy anyway. And if you expect your input to be modified even though it is passed by value, you better have unit tests 😉

    • I feel like I agree with you, but I’m not sure which part of the article each of your points is referencing. Yes, some non-pointer types can be modified out of scope (slices and maps use pointers under the hood, etc)

Comments are closed.