Closures
In this page:
func outer() func(param type) returnType {
captured := value
return func(param type) returnType {
// uses captured
}
}
What Makes a Closure
A closure is simply a function literal that refers to a variable declared outside of it -- Go automatically keeps that variable alive and accessible to the function for as long as the closure itself exists.
Example: What Makes a Closure
// Every Go file belongs to a package; main builds an executable
package main
// Import the fmt package
import "fmt"
// main is where the program starts running
func main() {
// Short declaration: create message and infer the type
message := "hello"
// Short declaration: create greet and infer the type
greet := func() {
// Print the values followed by a newline
fmt.Println(message)
}
greet()
}
Login to try C/C++/Java/PHP code in the editor
Closures Share, Not Copy, Captured Variables
Because a closure captures the variable itself rather than a snapshot of its value, changes made inside the closure are visible outside it, and changes made outside are visible the next time the closure runs.
Example: Closures Share, Not Copy, Captured Variables
// Every Go file belongs to a package; main builds an executable
package main
// Import the fmt package
import "fmt"
// main is where the program starts running
func main() {
// Short declaration: create count and infer the type
count := 0
// Short declaration: create increment and infer the type
increment := func() {
count++
}
increment()
increment()
// Print the values followed by a newline
fmt.Println("count:", count)
}
Login to try C/C++/Java/PHP code in the editor
Building a Counter Factory
A classic use of closures is a function that returns another function, which keeps its own private state alive between calls -- like a counter generator that hands back an independent, incrementing counter each time it's called.
Example: Building a Counter Factory
// Every Go file belongs to a package; main builds an executable
package main
// Import the fmt package
import "fmt"
// Define the function makeCounter
func makeCounter() func() int {
// Short declaration: create count and infer the type
count := 0
// Send func() int { back to the caller
return func() int {
count++
return count
}
}
// main is where the program starts running
func main() {
// Short declaration: create counter and infer the type
counter := makeCounter()
// Print the values followed by a newline
fmt.Println(counter())
fmt.Println(counter())
fmt.Println(counter())
}
Login to try C/C++/Java/PHP code in the editor
- Assuming each closure gets its own independent copy of a captured variable, when closures actually share a reference to the same variable.
- Creating closures in a loop pre-Go-1.22 and being surprised they all captured the same final loop variable value.
- Using a closure to mutate shared state from multiple goroutines without any synchronization, causing a data race.
- A closure is a function literal that references variables from outside its own body.
- Captured variables are shared by reference, not copied -- changes inside the closure are visible outside, and vice versa.
- Closures are commonly used to build function factories, like counters or accumulators.
- Since Go 1.22, each loop iteration gets a fresh variable, making closures inside loops behave intuitively.
Chapter Quiz — Complete all 7 topics to unlock
0/7 topics done
Complete these topics first: