← Все этапы
04 · ПАКЕТЫ И НАДЁЖНОСТЬУрок 27 из 3340 мин

Функциональные литералы и замыкания

Создаём функции на месте, передаём их как данные и сохраняем захваченные значения.

Счётчик как значение-функция

Сохраните программу в main.go и запустите командой go run main.go.

package main

import "fmt"

type transform func(int) int

func apply(values []int, transform transform) []int {
	result := make([]int, 0, len(values))
	for _, value := range values {
		result = append(result, transform(value))
	}
	return result
}

func makeMultiplier(factor int) transform {
	return func(value int) int {
		return value * factor
	}
}

func main() {
	values := []int{2, 4, 6}
	triple := makeMultiplier(3)
	fmt.Println(apply(values, triple))

	threshold := 5
	countAbove := 0
	visit := func(value int) {
		if value > threshold {
			countAbove++
		}
	}
	for _, value := range values {
		visit(value)
	}
	fmt.Println("больше порога:", countAbove)
}

В первом результате функция, созданная внутри makeMultiplier, умножает каждое число на сохранённый множитель. Во втором замыкание читает threshold и изменяет countAbove, объявленные во внешней функции.

Функция внутри выражения

Функциональный литерал — это объявление функции без имени, записанное как значение: func(value int) int { ... }. Его можно присвоить переменной, сразу вызвать или передать аргументом. Функции удобно передавать как callback, когда вызывающий код управляет перебором, а пользователь задаёт действие для каждого элемента.

В примере определён именованный тип функции transform. Он делает сигнатуру параметра apply короче и даёт понятное имя роли. Обычный именованный тип и псевдоним типа — разные конструкции: type transform func(int) int создаёт отдельное имя типа, а type transform = func(int) int объявляет alias.

Замыкание и захваченные переменные

Литерал может обращаться к переменным внешней области видимости. Такая функция вместе с доступом к этим переменным называется замыканием. makeMultiplier возвращает функцию, а параметр factor продолжает быть доступным после завершения вызова makeMultiplier: замыкание сохраняет окружение, необходимое для дальнейшей работы.

Замыкание захватывает переменную, а не снимок её значения в момент объявления. Если внешнее значение позже изменить, вызов замыкания увидит новое значение. Если нужна независимая копия, передайте значение параметром или сохраните его в отдельной переменной.

Состояние в замыкании удобно для счётчиков и небольшого контекста операции. Следите за тем, кто меняет захваченные переменные: несколько вызовов могут разделять одно и то же состояние. При одновременном доступе обычная переменная требует синхронизации так же, как и поле структуры.

Практика

Попробуйте сами

Создайте visitLines(lines []string, visit func(string)), которая вызывает callback для каждой строки. В main сделайте замыкание со счётчиками букв, цифр, пробелов и пунктуации; классифицируйте руны функциями пакета unicode. Используйте строки Go 1! и Да, 2..

Проверка результата

Как понять, что получилось

Отчёт содержит 4 буквы, 2 цифры, 2 пробела и 3 знака пунктуации. Счётчики обновляются внутри callback за счёт захвата переменных из main.

Функциональные литералы и замыкания | Go | WebSchool · Go