Day 6 - Anonymous Functions, Closures
Anonymous Functions
Anonymous functions are functions without a name. They are often used when we want to create inline functions.
Example:
package main
import "fmt"
func main() {
func() {
fmt.Println("Printing the body of the function")
}() // here we are calling the function itself
}
Similar to normal functions, we can provide parameters along with return types. We can assign an anonymous function to a variable and call the function using that variable.
Example:
package main
import "fmt"
func main() {
add := func(a, b int) int {
return a + b
}
fmt.Println(add(4, 4))
fmt.Println(add(1, 3))
}
Passing Anonymous Functions as Arguments
We can pass anonymous functions as arguments to other functions and call them within those functions.
Example:
package main
import "fmt"
// creating a function where i and j are parameters of type func(a, b int) string
func simpleFunction(i, j func(a, b int) string) {
str1 := i(5, 6) // calling the function i
str2 := j(4, 6) // calling the function j
fmt.Println(str1)
fmt.Println(str2)
}
func main() {
// creating anonymous function
add := func(a, b int) string {
sum := a + b
return fmt.Sprintf("%d is the value after addition", sum)
}
// creating another anonymous function
sub := func(a, b int) string {
val := b - a
if a > b {
val = a - b
}
return fmt.Sprintf("%d is the value after subtraction", val)
}
// calling simpleFunction with parameters add & sub
simpleFunction(add, sub)
}
Output:
11 is the value after addition
2 is the value after subtraction
Returning Anonymous Functions
We can return anonymous functions from other functions.
Example:
package main
import "fmt"
// creating a function which returns an anonymous function
func returnAnonymous() func(i, j int) string {
var anonymousFunction = func(i, j int) string {
sum := i + j
return fmt.Sprintf("%d is the sum of two numbers", sum)
}
return anonymousFunction
}
func main() {
anonymFunc := returnAnonymous()
outputString := anonymFunc(4, 5) // this function returns the string
fmt.Println(outputString)
}
Output:
9 is the sum of 2 numbers
Closures
Using anonymous functions, we can create closures. A closure is a special type of anonymous function that references variables declared outside of the function itself.
Example:
package main
import "fmt"
// likesCounter() returns a closure function
func likesCounter() func() int {
i := 0
// closure function that captures and updates 'i'
hitLike := func() int {
i++
return i
}
return hitLike
}
func main() {
// separate like counters for individual posts
post1 := likesCounter() // independent counter
post2 := likesCounter()
post3 := likesCounter()
post1()
post2()
post1()
post1()
post3()
post2()
fmt.Printf("Final likes for post1: %d\n", post1())
fmt.Printf("Final likes for post2: %d\n", post2())
fmt.Printf("Final likes for post3: %d\n", post3())
}
Output:
Final likes for post1: 4
Final likes for post2: 3
Final likes for post3: 2
Real-Life Use Cases of Closures in Go
| Use Case | Description |
| Custom Counters | Views, likes, retry attempts |
| Caching / Memoization | Storing results of expensive computations |
| Event Handlers | Handling user actions in web apps |
| Encapsulation | Creating private state without structs |
| Filtering / Mapping | Passing dynamic logic to loops or goroutines |
| Middleware in Web Frameworks | Used in Gin, Echo, Fiber, etc. |
Example: Memoization (Performance Optimization) – Fibonacci
package main
import "fmt"
// memoization/cache using closure function
func fibonacci() func(int) int {
cache := make(map[int]int)
var fib func(n int) int
fib = func(n int) int {
if n <= 1 {
return n
}
if val, exists := cache[n]; exists {
return val
}
cache[n] = fib(n-1) + fib(n-2)
return cache[n]
}
return fib
}
func main() {
f := fibonacci()
fmt.Println(f(10)) // calculates and caches
fmt.Println(f(10)) // returns from cache
f2 := fibonacci() // creates a new cache
fmt.Println(f2(9)) // calculates up to 9 and caches
}
Wrapping Up
Anonymous functions and closures are powerful features in Go that enable flexibility, modularity, and stateful behavior without relying on full struct definitions or global variables. They shine in scenarios where logic needs to be encapsulated, reused dynamically, or enhanced with memory-like behavior — such as counters, memoization, event handling, and functional-style programming.
By mastering these concepts, you not only write cleaner and more expressive Go code but also unlock patterns commonly used in production systems, web frameworks, and high-performance applications.
#GoLang #Backend #90DaysOfGo #Microservices #Development #SoftwareDevelopment #GoProgramming #BackendDevelopment #APIs #DevJourney #Programming