Summary: in this tutorial, you will learn how to assign a function to a variable, pass a function to another as an argument, and return a function from another function.
In Go, you may come across the phrase: Go functions are first-class citizens. This means that Go treats functions as other values. In other words, you can:
- Assign a function to a variable.
- Pass a function as an argument to another function.
- Return a function from a function.
Assigning a function to a variable
The following example illustrates how to assign a function to a variable:
package main
import "fmt"
func add(x int, y int) int {
return x + y
}
func subtract(x int, y int) int {
return x - y
}
func main() {
var fn = add
result := fn(10, 20)
fmt.Println(result)
fn = subtract
result = fn(20, 10)
fmt.Println(result)
}
Code language: Go (go)
How it works.
First, define two functions:
add
: returns the sum of two integers.subtract
: returns the difference between two integers.
Next, assign the add
function name to the variable fn
:
var fn = add
Code language: Go (go)
Notice that we don’t place the parentheses ()
after the add
function name.
Then, call the add
function via the fn
variable and assign the return value to the result
variable and display the result on the screen:
result := fn(10,20)
fmt.Println(result) // Output 30 ( 20 + 10 )
Code language: Go (go)
After that, assign the subtract
function name to the fn
variable:
fn = subtract
Code language: Go (go)
Finally, call the subtract
function via the fn
variable and display the return value on the screen:
result = fn(20, 10)
fmt.Println(result) // 10 (20 - 10)
Code language: Go (go)
In Go, a variable is always associated with a type. In this example, the type of the fn
variable is a function that accepts two integers and returns an integer. Go will infer the type of the fn
variable like this:
var fn func(x int, y int) int
Code language: Go (go)
We can assign both add
and subtract
functions to the fn
variable because these functions have the same signature:
func(x int, y int) int
Code language: Go (go)
Go allows you to declare type alias for functions. For example, you can declare the type alias for the function that has two integer parameters and returns an integer:
type op func(int, int) int
Code language: Go (go)
You can then use the op
type alias to declare the fn
variable as follows:
var fn op
Code language: Go (go)
Then you can assign any function that takes two integer parameters and returns an integer:
fn = add
Code language: Go (go)
Passing a function as an argument to another function
Go allows you to pass a function to another function as an argument. For example:
package main
import "fmt"
type op func(int, int) int
func add(x int, y int) int {
return x + y
}
func subtract(x int, y int) int {
return x - y
}
func calculate(x int, y int, fn op) int {
return fn(x, y)
}
func main() {
result := calculate(20, 10, add)
fmt.Println(result)
result = calculate(20, 10, subtract)
fmt.Println(result)
}
Code language: Go (go)
In this example:
Step 1. Define the op type alias for the function that accepts two integers and returns an integer:
type op func(int, int) int
Step 2. Define the calculate
function that takes two integer parameters and one fn
with the type op
:
func calculate(x int, y int, fn op) int
Code language: Go (go)
Step 3. Call the fn
function inside the calculate
function:
return fn(x, y)
Code language: Go (go)
Step 4. Call the calculate function and pass the add function name as an argument:
result := calculate(20, 10, add)
Code language: Go (go)
Notice that we also don’t place the parentheses after the add function name when passing to the calculate function.
Inside the calculate
function, the add
function will be called with two arguments 20 and 10:
add(20, 10)
Code language: Go (go)
Step 5. Call the calculate
function and pass the subtract
function name to it as an argument:
result = calculate(20, 10, subtract)
Code language: Go (go)
Similarly, the calculate function will call subtract via the fn
argument:
fn(20, 10)
Code language: Go (go)
It is equivalent to:
subtract(20, 10)
A practical example of passing a function as an argument to a function
The following example shows a practical example of passing a function to another function as an argument:
package main
import "fmt"
type predicate func(int) bool
func isEven(x int) bool {
return x%2 == 0
}
func isOdd(x int) bool {
return x%2 != 0
}
func filter(numbers []int, p predicate) []int {
var result []int
for _, n := range numbers {
if p(n) {
result = append(result, n)
}
}
return result
}
func main() {
numbers := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
evenNumbers := filter(numbers, isEven)
fmt.Println(evenNumbers)
oddNumbers := filter(numbers, isOdd)
fmt.Println(oddNumbers)
}
Code language: Go (go)
How it works.
Step 1. Define a type alias for a function that accepts an integer and returns a boolean:
type predicate func(int) bool
Code language: Go (go)
Step 2. Define an isEven
function that returns true if a number is odd:
func isEven(x int) bool {
return x%2 == 0
}
Code language: Go (go)
Step 3. Define a filter
function that filters elements of an integer array using the predicate
function:
func filter(numbers []int, p predicate) []int {
var result []int
for _, n := range numbers {
if p(n) {
result = append(result, n)
}
}
return result
}
Code language: Go (go)
How the filter function works.
First, declare an integer array (result
) that stores the numbers when passing to the predicate
function will make it return true:
var result []int
Code language: Go (go)
Second, iterate over the elements of the numbers array using a for range loop:
for _, n := range numbers {
Code language: Go (go)
Third, append the number to the result
array if it satisfies the predicate
function:
if p(n) {
result = append(result, n)
}
Code language: Go (go)
Finally, return the result
array:
return result
Code language: Go (go)
Step 4. Declare and initialize an integer array:
numbers := [] int {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
Code language: Go (go)
Step 5. Pass the numbers array and isEven
function to the filter
function to return only even integers from the numbers
array.
evenNumbers := filter(numbers, isEven)
fmt.Println(evenNumbers)
Code language: Go (go)
Step 6. Pass the numbers array and isOdd
function to the filter
function to return only odd integers from the numbers
array.
oddNumbers := filter(numbers, isOdd)
fmt.Println(oddNumbers)
Code language: Go (go)
The filter function is known as a high-order function because it accepts a function as an argument.
A high-order function is a function that accepts another function as an argument or return a function as a return value
Returning a function from a function
The following example shows how to return a function from a function:
package main
import "fmt"
func adder(x int) func(int) int {
return func(y int) int {
return x + y
}
}
func main() {
add2 := adder(2)
fmt.Println(add2(10)) // Output: 12
add5 := adder(5)
fmt.Println(add5(10)) // Output: 15
}
Code language: Go (go)
Output:
12
15
Code language: Go (go)
How it works:
Step 1. Define the adder
function that accepts an integer and returns a function that accepts an integer and returns an integer:
func adder(x int) func(int) int
Code language: Go (go)
Step 2. Return a function literal that accepts an integer and returns an integer:
return func(y int) int {
return x + y
}
Code language: Go (go)
Inside the function literal, return the sum of x and y.
Step 3. Call the adder
function with a number 2 and assign the return value, which is a function, to the add2
variable:
add2 := adder(2)
Code language: Go (go)
Note that the type of the add2
is a function that accepts an integer and returns an integer.
Step 4. Call the add2
function with 10 as an argument and print out the result:
result := add2(10)
fmt.Println(result) // Output: 12
Code language: Go (go)
Step 5. Call the adder function with the number 5 as an argument:
add5 := adder(5)
Code language: Go (go)
Step 6. Call the add5
function with 10 as an argument and print out the result:
result = add5(10)
fmt.Println(result) // Output: 15
Code language: Go (go)
Summary
- Functions are first-class citizens means that you can assign a function to a variable, pass a function as an argument to a function, and return a function from a function.