Перейти до основного вмісту
Модуль 3 · Урок 4 із 514/50 у курсі~12 min
Модульні уроки (4/5)

Замикання та функції як значення

У Go функції є значеннями першого класу: їх можна призначати змінні, передані іншим функціям і повернуті. Закриття - це a літерал функції (анонімний), який захоплює змінні середовище, в якому воно визначається.

Літерал функції

Функція без назви, записана вбудовано. Ви телефонуєте негайно або призначити це:

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

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

Тип greet — func(string).

Захоплення середовища: закриття

Функціональний літерал може читати та змінювати видимі змінні його лексичний обсяг, навіть після повернення зовнішньої функції:

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

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

n "живе" до тих пір, поки принаймні одне закриття посилається на нього. Кожен дзвінок до counter() створює новий незалежний n.

Закриття як зворотний виклик

Дуже поширений шаблон:

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

Закриття фіксує nums та визначає порядок.

Функції як параметри

Щоб прийняти функцію як параметр, запишіть її тип:

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]

Якщо підпис стає важко читати, визначте псевдонім типу:

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

Спробуйте

вправи#go.m3.l4.e1
Спроби: 0Завантаження…

Визначте counter(), який повертає закриття: кожен виклик закриття збільшується та повертає внутрішній лічильник.

Завантаження редактора…
Показати підказку

`n` має бути оголошено ПЕРЕД поверненням; закриття захоплює його.

Рішення доступне після 3 спроб

вправи#go.m3.l4.e2
Спроби: 0Завантаження…

Призначте f функціональний літерал, який друкує «ciao», а потім викличте його.

Завантаження редактора…
Показати підказку

Синтаксис: `f := func() { ... }` потім `f()`.

Рішення доступне після 3 спроб

Quiz#go.m3.l4.e3
Готовий

Що це друкує? (стежте за обсягом закриття)

Go
mk := func() func() int {
    x := 0
    return func() int { x++; return x }
}
a := mk()
b := mk()
fmt.Println(a(), a(), b())
Варіанти відповідей

Підведення підсумків

  • Функції першокласні: призначаються, передаються, повертаються.
  • Літерал функції: func(params) ret { ... }, анонімний.
  • Закриття: фіксує змінні лексичного обсягу, зберігає їх живими.
  • Явний тип функції в параметрах: func(int) int.
  • Починаючи з Go 1.22, кожна ітерація for має власну копію змінної циклу.