Types you define · 3 MIN READ

A pointer is for changing something, not for speed

Say when a pointer is required and when it is only noise.

Go passes everything by value. A struct handed to a function is copied, and writing to the copy changes nothing the caller can see. A pointer is how you say "the same one", and & and * are the whole syntax: &value takes an address, *pointer reads through one. Field access needs no * — p.X works on a pointer as well as a value, which is why you rarely see the star in ordinary code.

There is no pointer arithmetic. A Go pointer either points at something or is nil, and that is all it can do — which is why passing one is safe in a way it is not in C.

The reason to use one is mutation. "Pointers are faster" is a guess: for a small struct the copy is often cheaper than the indirection and the extra work the garbage collector inherits. Measure before believing it, and until you have, choose based on whether the callee needs to change what it was given.

SEE THE IDEA

Two names can reach one value

  1. 01

    One value

    go
    count := 4

    The storage being referred to

  2. 02

    First pointer

    go
    p := &count

    Refers to count

  3. 03

    Second pointer

    go
    q := p

    Refers to that same count

Assigning through either pointer changes the one shared value.

In practice

Use a pointer to communicate shared identity or a permitted mutation. A pointer is itself copied when passed to a function, so reassigning the parameter changes only that local pointer; assigning through it changes the pointed-to value. Check nil before dereferencing an optional pointer.

Watch out

A pointer does not automatically make code faster. Allocation and copying behavior depend on the program and compiler.

Official reference ↗

Read and predict

go
package main

import "fmt"

type Settings struct {
	Retries int
}

func byValue(s Settings) {
	s.Retries = 9
}

func byPointer(s *Settings) {
	s.Retries = 9
}

func main() {
	s := Settings{Retries: 1}
	byValue(s)
	fmt.Println(s.Retries)
	byPointer(&s)
	fmt.Println(s.Retries)
}

What are the two numbers, and why are they different?

Try it yourself

Trace each value and write down your reasoning. Copy the source into GopherForge or your local Go environment to compile and check it. This web page does not execute your code or send it to a compiler service.

Progress stays in this browser. No account needed.