Types you define · 3 MIN READ

A function is a value, and it remembers where it came from

Return a function that carries state, and know what it captured.

Functions are values: they can be stored, passed and returned. A function literal keeps access to the variables it captures, rather than taking an automatic snapshot of their values.

Two closures capturing the same variable see each other's updates. Separate calls to a factory create separate environments. When you need a snapshot, make an explicit copy for the closure to capture.

Since Go 1.22, iteration variables declared by a loop get a fresh variable on each iteration. A loop assigning to a variable declared outside it still reuses that variable. The distinction between := and = matters here too.

SEE THE IDEA

The function keeps access to its environment

  1. 01

    Create

    go
    total := 0

    A captured variable is created

  2. 02

    Capture

    go
    func() { total++ }

    The closure uses that variable

  3. 03

    Call again

    go
    next()

    It sees the updated total

Calls to one returned closure share its captured variables.

In practice

A closure is a useful way to return a small stateful operation without exposing a struct. Separate calls to the factory create separate captured state. Multiple closures created in one environment may share that state, so concurrent use still needs synchronization.

Watch out

Capturing a variable does not freeze its current value. Copy it deliberately when the callback needs a snapshot.

Official reference ↗

Work through the exercise

go
package main

// Counter should return a function that returns 1 the first time it
// is called, 2 the second time, and so on. Two counters made by two
// calls must not share their count.

func main() {
	next := Counter()
	println(next(), next())
}
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.