In Go, functions are first-class citizens, meaning they can be treated like any other variable. This includes being returned from other functions. This feature is very useful for creating higher-order functions and allows for powerful functional programming patterns.
Table of Contents
Basic Example
Let's start with a basic example of returning a function from another function in Go:
package main
import "fmt"
// function returns another function
func add(a, b int) func() int {
return func() int {
return a + b
}
}
func main() {
sumFunc := add(10, 20)
fmt.Println(sumFunc()) // Output: 30
}
In this example, the add function returns a closure that computes the sum of a and b. The returned function does not take any parameters, and its body has access to the variables a and b, captured from its outer scope.
Intermediate Example
In more complex applications, we might want our returned functions to be configurable. We can achieve this by passing additional parameters to the closure itself:
package main
import "fmt"
// multiplier function returns a function
func multiplier(x int) func(int) int {
return func(y int) int {
return x * y
}
}
func main() {
double := multiplier(2)
triple := multiplier(3)
fmt.Println(double(4)) // Output: 8
fmt.Println(triple(5)) // Output: 15
}
Here, the multiplier function returns another function that multiples any given number by a fixed x, demonstrating parameterized functional behavior.
Advanced Example
For an advanced example, consider using function returns in a scenario that modulates behavior dynamically:
package main
import (
"errors"
"fmt"
"strings"
)
// stringTransformer returns a function based on the choice
func stringTransformer(choice string) (func(string) (string, error), error) {
if choice == "upper" {
return func(s string) (string, error) {
return strings.ToUpper(s), nil
}, nil
} else if choice == "lower" {
return func(s string) (string, error) {
return strings.ToLower(s), nil
}, nil
}
return nil, errors.New("unknown choice")
}
func main() {
upperFunc, err := stringTransformer("upper")
if err != nil {
fmt.Println(err)
return
}
lowerFunc, _ := stringTransformer("lower")
fmt.Println(upperFunc("hello")) // Output: HELLO
fmt.Println(lowerFunc("WORLD")) // Output: world
}
In this example, the function stringTransformer returns different functions based on the string choice parameter. This kind of functionality allows dynamic behavior alteration, based on runtime decisions.
Returning functions as values opens up a myriad of programming possibilities, enabling developers to write more composable, modular, and reusable Go code.