Skip to content

Go Closures

A closure is a function that "closes over" variables from its surrounding scope. This means the function can remember and access these variables even after the outer function has finished executing.

Basic Example

Closures are often used to create functions with "memory" or state.

package main

import "fmt"

func intSeq() func() int {
    i := 0
    return func() int {
        i++
        return i
    }
}

func main() {
    // nextInt is a closure that "captures" the variable i
    nextInt := intSeq()

    fmt.Println(nextInt()) // 1
    fmt.Println(nextInt()) // 2
    fmt.Println(nextInt()) // 3

    // To confirm that the state is unique to that function instance:
    newInts := intSeq()
    fmt.Println(newInts()) // 1
}

Why use Closures?

  1. State Management: They allow functions to maintain state without using global variables.
  2. Function Factories: You can create specialized functions on the fly.
  3. Callbacks: Frequently used in asynchronous code or when passing logic to other functions.

Common Pitfall: Loop Variables

When creating closures inside a loop, they all share the same loop variable if you aren't careful.

1
2
3
4
5
6
// Be careful with this pattern
for i := 0; i < 3; i++ {
    go func() {
        fmt.Println(i) // Might print 3, 3, 3
    }()
}

To fix this, pass the variable as a parameter or redefine it inside the loop:

1
2
3
4
5
6
for i := 0; i < 3; i++ {
    i := i // Create a unique instance for each closure
    go func() {
        fmt.Println(i)
    }()
}