Go Functions are First-class Citizens

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 = addCode 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 = subtractCode 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) intCode 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) intCode 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) intCode language: Go (go)

You can then use the op type alias to declare the fn variable as follows:

var fn opCode language: Go (go)

Then you can assign any function that takes two integer parameters and returns an integer:

fn = addCode 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) intCode 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) boolCode 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 []intCode 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 resultCode 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
15Code 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) intCode 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: 12Code 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: 15Code 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.
Was this tutorial helpful?