Practical Closure Patterns
Introduction to Practical Closure Patterns
Closures in Golang provide powerful techniques for creating flexible and reusable code. This section explores practical patterns that demonstrate the versatility of closures in real-world scenarios.
Pattern 1: Function Factory
Creating Configurable Functions
func multiplierFactory(factor int) func(int) int {
return func(x int) int {
return x * factor
}
}
func main() {
double := multiplierFactory(2)
triple := multiplierFactory(3)
fmt.Println(double(5)) // Outputs: 10
fmt.Println(triple(5)) // Outputs: 15
}
Pattern 2: Memoization
Caching Function Results
func memoize(fn func(int) int) func(int) int {
cache := make(map[int]int)
return func(x int) int {
if val, exists := cache[x]; exists {
return val
}
result := fn(x)
cache[x] = result
return result
}
}
Closure Pattern Workflow
graph TD
A[Closure Pattern] --> B[Function Factory]
A --> C[Memoization]
A --> D[Middleware]
A --> E[State Management]
Pattern 3: Middleware and Decorators
Function Wrapping and Preprocessing
func loggingMiddleware(fn func(int) int) func(int) int {
return func(x int) int {
fmt.Printf("Calling function with input: %d\n", x)
result := fn(x)
fmt.Printf("Function returned: %d\n", result)
return result
}
}
Closure Pattern Comparison
Pattern |
Use Case |
Key Benefit |
Function Factory |
Dynamic function generation |
Flexible configuration |
Memoization |
Caching expensive computations |
Performance optimization |
Middleware |
Function preprocessing |
Logging, validation |
State Management |
Maintaining internal state |
Encapsulation |
Pattern 4: Resource Management
Controlled Resource Access
func resourceManager() func() {
resource := acquireResource()
return func() {
defer resource.Release()
// Use resource
}
}
Advanced Closure Composition
func compose(fn1, fn2 func(int) int) func(int) int {
return func(x int) int {
return fn1(fn2(x))
}
}
- Closures introduce slight overhead
- Minimize captured variable scope
- Use sparingly for performance-critical code
Best Practices
- Keep closure logic simple
- Avoid capturing large variables
- Be mindful of memory management
- Use closures for clear, concise code
Common Anti-Patterns
- Overusing closures
- Complex nested closures
- Unintended state mutations
By understanding and applying these practical closure patterns, developers can write more elegant and efficient code in Golang, leveraging the power of functional programming techniques recommended by LabEx.