Skip to main content
eLearner.app
Module 3 · Lesson 4 of 514/50 in the course~12 min
Module lessons (4/5)

Closures and functions as values

In Go, functions are first-class values: they can be assigned to variables, passed to other functions, and returned. A closure is a function literal (anonymous) that captures the variables of the environment in which it is defined.

Function literal

A function with no name, written inline. You call it immediately or assign it:

Go
greet := func(name string) {
    fmt.Println("ciao", name)
}
greet("Anna")

// invocata immediatamente:
func() { fmt.Println("subito") }()

The type of greet is func(string).

Capturing the environment: closure

The function literal can read and modify the variables visible in its lexical scope, even after the outer function has returned:

Go
func counter() func() int {
    n := 0
    return func() int {
        n++
        return n
    }
}

c := counter()
fmt.Println(c(), c(), c())  // 1 2 3

n "lives" as long as at least one closure references it. Each call to counter() creates a new, independent n.

Closure as callback

A very common pattern:

Go
nums := []int{3, 1, 2}
sort.Slice(nums, func(i, j int) bool {
    return nums[i] < nums[j]
})

The closure captures nums and defines the ordering.

Functions as parameters

To accept a function as a parameter, write out its type:

Go
func apply(nums []int, f func(int) int) []int {
    out := make([]int, len(nums))
    for i, n := range nums {
        out[i] = f(n)
    }
    return out
}

double := func(x int) int { return x * 2 }
apply([]int{1, 2, 3}, double)   // [2 4 6]

If the signature becomes hard to read, define a type alias:

Go
type Transform func(int) int
func apply(nums []int, f Transform) []int { ... }

Try it

Exercise#go.m3.l4.e1
Attempts: 0Loading…

Define counter() that returns a closure: each call to the closure increments and returns an internal counter.

Loading editor…
Show hint

`n` must be declared BEFORE the return; the closure captures it.

Solution available after 3 attempts

Exercise#go.m3.l4.e2
Attempts: 0Loading…

Assign to f a function literal that prints 'ciao', then call it.

Loading editor…
Show hint

Syntax: `f := func() { ... }` then `f()`.

Solution available after 3 attempts

Quiz#go.m3.l4.e3
Ready

What does this print? (watch out for closure scope)

Go
mk := func() func() int {
    x := 0
    return func() int { x++; return x }
}
a := mk()
b := mk()
fmt.Println(a(), a(), b())
Answer options

Recap

  • Functions are first-class: assignable, passable, returnable.
  • Function literal: func(params) ret { ... }, anonymous.
  • Closure: captures the variables of the lexical scope, keeps them alive.
  • Explicit function type in parameters: func(int) int.
  • Since Go 1.22, every for iteration has its own copy of the loop variable.