Модульні уроки (4/5)
Замикання та функції як значення
У Go функції є значеннями першого класу: їх можна призначати змінні, передані іншим функціям і повернуті. Закриття - це a літерал функції (анонімний), який захоплює змінні середовище, в якому воно визначається.
Літерал функції
Функція без назви, записана вбудовано. Ви телефонуєте негайно або призначити це:
greet := func(name string) {
fmt.Println("ciao", name)
}
greet("Anna")
// invocata immediatamente:
func() { fmt.Println("subito") }()Тип greet — func(string).
Захоплення середовища: закриття
Функціональний літерал може читати та змінювати видимі змінні його лексичний обсяг, навіть після повернення зовнішньої функції:
func counter() func() int {
n := 0
return func() int {
n++
return n
}
}
c := counter()
fmt.Println(c(), c(), c()) // 1 2 3n "живе" до тих пір, поки принаймні одне закриття посилається на нього. Кожен дзвінок до
counter() створює новий незалежний n.
Закриття як зворотний виклик
Дуже поширений шаблон:
nums := []int{3, 1, 2}
sort.Slice(nums, func(i, j int) bool {
return nums[i] < nums[j]
})Закриття фіксує nums та визначає порядок.
Функції як параметри
Щоб прийняти функцію як параметр, запишіть її тип:
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]Якщо підпис стає важко читати, визначте псевдонім типу:
type Transform func(int) int
func apply(nums []int, f Transform) []int { ... }Спробуйте
Визначте counter(), який повертає закриття: кожен виклик закриття збільшується та повертає внутрішній лічильник.
Показати підказку
`n` має бути оголошено ПЕРЕД поверненням; закриття захоплює його.
Рішення доступне після 3 спроб
Призначте f функціональний літерал, який друкує «ciao», а потім викличте його.
Показати підказку
Синтаксис: `f := func() { ... }` потім `f()`.
Рішення доступне після 3 спроб
Що це друкує? (стежте за обсягом закриття)
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 має власну копію змінної циклу.