GO / CHAPTER 05

Pointers and controlled mutation

Intermediate

Distinguish copying a value from sharing the value it references.

By the end of this chapter

  • Trace pointer updates
  • Choose pointer or value receivers
  • Recognize shallow copying of composite values

The idea

A pointer holds the address of a value. The address operator & obtains a pointer, and * accesses the pointed-to value. Passing an ordinary struct to a function copies that struct value; passing its pointer lets the function modify the shared original. A nil pointer must not be dereferenced. Make mutation visible in the function contract so callers understand which state can change.

A copied struct can still contain slices, maps, or pointers that refer to shared data. Copying the outer struct therefore does not promise a completely independent object graph. A pointer receiver is useful when a method intentionally updates the receiver. A value receiver operates on a copy of the receiver, although nested references can still expose shared mutable state.

Go example
package main
import "fmt"
type Counter struct{ N int }
func bump(c *Counter){ c.N++ }
func main(){ a := Counter{2}; b := a; bump(&b); fmt.Println(a.N,b.N) }
Result
2 3

The initial assignment copies the integer field. Passing b’s address permits bump to update b alone.

Try it yourself

Write a pointer-receiver method that rejects negative increments without changing the counter.

Use your own editor for this exercise. Runnable challenges on CodeQuest are available for JavaScript, Python, and SQL.

CHECK YOUR UNDERSTANDING

Chapter checkpoint

What is printed?
n := 3
p := &n
*p += 4
fmt.Println(n)