Closures / Anonymous Functions
In Go, functions are first-class values — you can assign them to variables, pass them as arguments, or return them from other functions. A closure is a function that "closes over" the variables in scope at the time it is defined, and is a fundamental pattern in functional programming.
Syntax
// Anonymous function (immediately invoked)
func() {
// body
}()
// Assign to a variable.
add := func(a, b int) int {
return a + b
}
result := add(3, 4) // 7
// Closure (captures a variable from the outer scope)
counter := 0
increment := func() int {
counter++ // references the outer variable counter
return counter
}
// Higher-order function that returns a function (closure factory)
func makeAdder(x int) func(int) int {
return func(y int) int {
return x + y // x is captured by the closure
}
}
Common Closure Patterns
| Pattern | Description |
|---|---|
| Immediately invoked function | Defines and calls a function in one expression. Useful for initialization and scope isolation. |
| State encapsulation | The closure holds a variable that cannot be accessed from outside, achieving private state. |
| Factory function | Generates and returns a function pre-configured with a given parameter. |
| Callback | Uses an anonymous function when passing a function as an argument. |
Sample Code
package main
import "fmt"
// Factory function that creates a counter.
func makeCounter(start int) func() int {
count := start
return func() int {
count++ // count is captured by the closure
return count
}
}
// Factory function that creates a multiplier function.
func multiplier(factor int) func(int) int {
return func(n int) int {
return n * factor
}
}
// Higher-order function that accepts a function as an argument.
func apply(nums []int, fn func(int) int) []int {
result := make([]int, len(nums))
for i, n := range nums {
result[i] = fn(n)
}
return result
}
func main() {
// Encapsulate state with closures.
counter1 := makeCounter(0)
counter2 := makeCounter(10) // each has its own independent state
fmt.Println(counter1()) // 1
fmt.Println(counter1()) // 2
fmt.Println(counter2()) // 11
fmt.Println(counter1()) // 3 (not affected by counter2)
fmt.Println()
// Generate customized functions using a factory.
double := multiplier(2)
triple := multiplier(3)
nums := []int{1, 2, 3, 4, 5}
fmt.Println("doubled:", apply(nums, double))
fmt.Println("tripled:", apply(nums, triple))
fmt.Println()
// Pass an anonymous function inline.
fmt.Println("squared:", apply(nums, func(n int) int {
return n * n
}))
// Initialization with an immediately invoked function
result := func(a, b int) int {
return a + b
}(100, 200)
fmt.Println("immediately invoked result:", result)
}
Notes
In Go, functions are treated as first-class values. Because a closure holds a reference to the captured variable, any changes made through the closure affect the original variable. This behavior enables a design similar to object-oriented encapsulation.
A well-known bug occurs when launching goroutines inside a loop: the closure may not capture the loop variable correctly. Pass the loop variable as an argument to the closure, or create a local copy inside the loop body. Note that Go 1.22 changed how loop variables are scoped.
For variadic arguments, see Variadic Arguments. For combining closures with goroutines, see Goroutine.
If you find any errors or copyright issues, please contact us.