Skip to main content
โšก Calmops

Anonymous Functions and Closures

Anonymous Functions and Closures

Anonymous functions and closures are powerful features in Go that enable functional programming patterns and elegant code organization.

Anonymous Functions

Basic Anonymous Function

package main

import "fmt"

func main() {
    // Anonymous function
    func() {
        fmt.Println("Hello from anonymous function")
    }()

    // Anonymous function with parameters
    func(name string) {
        fmt.Printf("Hello, %s!\n", name)
    }("Alice")

    // Anonymous function with return value
    result := func(a, b int) int {
        return a + b
    }(5, 3)
    fmt.Println("Result:", result)
}

Assigning to Variables

package main

import "fmt"

func main() {
    // Assign anonymous function to variable
    greet := func(name string) string {
        return fmt.Sprintf("Hello, %s!", name)
    }

    fmt.Println(greet("Alice"))
    fmt.Println(greet("Bob"))
}

Closures

Basic Closure

package main

import "fmt"

func main() {
    x := 10

    // Closure captures x
    f := func() {
        fmt.Println("x is", x)
    }

    f()  // x is 10

    x = 20
    f()  // x is 20
}

Closure with State

package main

import "fmt"

func counter() func() int {
    count := 0
    return func() int {
        count++
        return count
    }
}

func main() {
    c1 := counter()
    fmt.Println(c1())  // 1
    fmt.Println(c1())  // 2
    fmt.Println(c1())  // 3

    c2 := counter()
    fmt.Println(c2())  // 1 (separate closure)
}

Closure Modifying Captured Variables

package main

import "fmt"

func makeAdder(x int) func(int) int {
    return func(y int) int {
        x += y
        return x
    }
}

func main() {
    add5 := makeAdder(5)
    fmt.Println(add5(3))  // 8
    fmt.Println(add5(2))  // 10
    fmt.Println(add5(1))  // 11
}

Functional Patterns

Map Function

package main

import "fmt"

func mapInts(nums []int, f func(int) int) []int {
    result := make([]int, len(nums))
    for i, n := range nums {
        result[i] = f(n)
    }
    return result
}

func main() {
    nums := []int{1, 2, 3, 4, 5}

    // Double each number
    doubled := mapInts(nums, func(n int) int {
        return n * 2
    })
    fmt.Println(doubled)  // [2 4 6 8 10]

    // Square each number
    squared := mapInts(nums, func(n int) int {
        return n * n
    })
    fmt.Println(squared)  // [1 4 9 16 25]
}

Filter Function

package main

import "fmt"

func filterInts(nums []int, f func(int) bool) []int {
    var result []int
    for _, n := range nums {
        if f(n) {
            result = append(result, n)
        }
    }
    return result
}

func main() {
    nums := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}

    // Filter even numbers
    evens := filterInts(nums, func(n int) bool {
        return n%2 == 0
    })
    fmt.Println(evens)  // [2 4 6 8 10]

    // Filter numbers > 5
    large := filterInts(nums, func(n int) bool {
        return n > 5
    })
    fmt.Println(large)  // [6 7 8 9 10]
}

Reduce Function

package main

import "fmt"

func reduceInts(nums []int, initial int, f func(int, int) int) int {
    result := initial
    for _, n := range nums {
        result = f(result, n)
    }
    return result
}

func main() {
    nums := []int{1, 2, 3, 4, 5}

    // Sum
    sum := reduceInts(nums, 0, func(acc, n int) int {
        return acc + n
    })
    fmt.Println("Sum:", sum)  // 15

    // Product
    product := reduceInts(nums, 1, func(acc, n int) int {
        return acc * n
    })
    fmt.Println("Product:", product)  // 120
}

Defer with Closures

Cleanup with Closure

package main

import "fmt"

func processFile(filename string) {
    file := openFile(filename)
    defer func() {
        fmt.Println("Closing file:", filename)
        file.Close()
    }()

    fmt.Println("Processing file:", filename)
}

type File struct {
    name string
}

func (f *File) Close() {
    fmt.Printf("File %s closed\n", f.name)
}

func openFile(name string) *File {
    fmt.Printf("File %s opened\n", name)
    return &File{name: name}
}

func main() {
    processFile("data.txt")
}

Closure Gotchas

Loop Variable Capture

package main

import "fmt"

func main() {
    // Common mistake
    var funcs []func()
    for i := 0; i < 3; i++ {
        funcs = append(funcs, func() {
            fmt.Println(i)  // All print 3
        })
    }

    for _, f := range funcs {
        f()
    }
    // Output: 3 3 3
}

Correct Loop Variable Capture

package main

import "fmt"

func main() {
    // Correct approach
    var funcs []func()
    for i := 0; i < 3; i++ {
        i := i  // Create new variable in each iteration
        funcs = append(funcs, func() {
            fmt.Println(i)
        })
    }

    for _, f := range funcs {
        f()
    }
    // Output: 0 1 2
}

Using Function Parameter

package main

import "fmt"

func main() {
    // Best approach
    var funcs []func()
    for i := 0; i < 3; i++ {
        funcs = append(funcs, func(n int) func() {
            return func() {
                fmt.Println(n)
            }
        }(i))
    }

    for _, f := range funcs {
        f()
    }
    // Output: 0 1 2
}

Best Practices

โœ… Good: Use Closures for State

// DO: Use closures to encapsulate state
func newCounter() func() int {
    count := 0
    return func() int {
        count++
        return count
    }
}

โœ… Good: Use Anonymous Functions for Callbacks

// DO: Use anonymous functions for callbacks
go func() {
    fmt.Println("Running in goroutine")
}()

โŒ Bad: Capture Loop Variables Incorrectly

// DON'T: Capture loop variables without care
for i := 0; i < 3; i++ {
    go func() {
        fmt.Println(i)  // All print 3
    }()
}

โœ… Good: Document Closure Behavior

// DO: Document what variables are captured
// makeMultiplier returns a function that multiplies by factor
func makeMultiplier(factor int) func(int) int {
    return func(x int) int {
        return x * factor
    }
}

Summary

Anonymous functions and closures provide:

  1. Function literals for inline functions
  2. Closures for capturing variables
  3. Functional patterns like map, filter, reduce
  4. State encapsulation without classes
  5. Elegant callbacks and handlers

These features enable powerful functional programming in Go.

Comments