Go Closures
Anonymous functions that capture variables from their environment
🔒 What are Go Closures?
Closures are anonymous functions that can access variables from their surrounding scope. They "close over" variables, maintaining access to them even after the outer function returns.
// Function returning a closure
func counter() func() int {
count := 0
return func() int {
count++
return count
}
}
func main() {
increment := counter()
fmt.Println(increment()) // 1
fmt.Println(increment()) // 2
}
Output:
1
2
Key Closure Concepts
Anonymous
Functions without names
func() {
fmt.Println("Anonymous")
}()
Variable Capture
Access outer scope variables
x := 10
func() {
fmt.Println(x) // Captures x
}()
State Persistence
Variables persist between calls
// count persists across calls
Function Factory
Create specialized functions
adder := makeAdder(5)
result := adder(3) // 8
🔹 Basic Closure Examples
Simple closures to understand the concept:
package main
import "fmt"
func main() {
// Simple anonymous function
func() {
fmt.Println("Hello from anonymous function!")
}()
// Closure capturing variable
message := "Hello from closure"
greet := func() {
fmt.Println(message)
}
greet()
// Closure with parameters
name := "Alice"
sayHello := func(greeting string) {
fmt.Printf("%s, %s!\n", greeting, name)
}
sayHello("Hi")
sayHello("Good morning")
}
Output:
Hello from anonymous function!
Hello from closure
Hi, Alice!
Good morning, Alice!
🔹 Function Factories
Functions that return customized closures:
package main
import "fmt"
// Create adder function
func makeAdder(x int) func(int) int {
return func(y int) int {
return x + y
}
}
// Create multiplier function
func makeMultiplier(factor int) func(int) int {
return func(n int) int {
return n * factor
}
}
// Create greeting function
func makeGreeter(greeting string) func(string) {
return func(name string) {
fmt.Printf("%s, %s!\n", greeting, name)
}
}
func main() {
// Create specialized adders
add5 := makeAdder(5)
add10 := makeAdder(10)
fmt.Println("5 + 3 =", add5(3))
fmt.Println("10 + 7 =", add10(7))
// Create multipliers
double := makeMultiplier(2)
triple := makeMultiplier(3)
fmt.Println("Double 6:", double(6))
fmt.Println("Triple 4:", triple(4))
// Create greeters
englishGreet := makeGreeter("Hello")
spanishGreet := makeGreeter("Hola")
englishGreet("Bob")
spanishGreet("Carlos")
}
Output:
5 + 3 = 8
10 + 7 = 17
Double 6: 12
Triple 4: 12
Hello, Bob!
Hola, Carlos!
🔹 Stateful Closures
Closures that maintain state between calls:
package main
import "fmt"
// Counter closure
func makeCounter() func() int {
count := 0
return func() int {
count++
return count
}
}
// Bank account closure
func makeBankAccount(initialBalance float64) (func(float64), func(float64), func() float64) {
balance := initialBalance
deposit := func(amount float64) {
balance += amount
fmt.Printf("Deposited $%.2f. Balance: $%.2f\n", amount, balance)
}
withdraw := func(amount float64) {
if amount <= balance {
balance -= amount
fmt.Printf("Withdrew $%.2f. Balance: $%.2f\n", amount, balance)
} else {
fmt.Println("Insufficient funds!")
}
}
getBalance := func() float64 {
return balance
}
return deposit, withdraw, getBalance
}
func main() {
// Counter example
counter1 := makeCounter()
counter2 := makeCounter()
fmt.Println("Counter 1:", counter1()) // 1
fmt.Println("Counter 1:", counter1()) // 2
fmt.Println("Counter 2:", counter2()) // 1 (independent)
fmt.Println("---")
// Bank account example
deposit, withdraw, getBalance := makeBankAccount(100.0)
fmt.Printf("Initial balance: $%.2f\n", getBalance())
deposit(50.0)
withdraw(30.0)
withdraw(200.0) // Should fail
}
Output:
Counter 1: 1
Counter 1: 2
Counter 2: 1
---
Initial balance: $100.00
Deposited $50.00. Balance: $150.00
Withdrew $30.00. Balance: $120.00
Insufficient funds!