Ответ
В Go функции являются гражданами первого класса (first-class citizens). Это означает, что их можно присваивать переменным, передавать в качестве аргументов другим функциям и возвращать из них. Функции, которые принимают другие функции в качестве аргументов или возвращают их, называются функциями высшего порядка (higher-order functions).
Способы передачи функции как параметра
Существует два основных способа это сделать:
1. Прямое указание сигнатуры функции
Вы можете напрямую в списке аргументов указать тип функции, которую ожидаете получить.
package main
import "fmt"
// process принимает число и функцию, которая будет это число обрабатывать.
// Тип функции-аргумента: func(int) int (принимает int, возвращает int)
func process(value int, action func(int) int) int {
fmt.Printf("Выполняем действие над числом %dn", value)
return action(value)
}
// double - конкретная функция, соответствующая сигнатуре func(int) int
func double(n int) int {
return n * 2
}
func main() {
// Передаем именованную функцию 'double'
result1 := process(5, double)
fmt.Printf("Результат: %dnn", result1) // Результат: 10
// Передаем анонимную функцию прямо в вызове
result2 := process(5, func(n int) int {
return n * n
})
fmt.Printf("Результат: %dn", result2) // Результат: 25
}
2. Использование именованного типа функции
Для улучшения читаемости и переиспользования сложных сигнатур можно объявить собственный тип функции с помощью ключевого слова type
.
package main
import "fmt"
// объявляем собственный тип для функции, которая принимает и возвращает int
type IntOperation func(int) int
// applyOperation использует наш новый тип для большей ясности
func applyOperation(value int, op IntOperation) int {
return op(value)
}
func increment(n int) int {
return n + 1
}
func decrement(n int) int {
return n - 1
}
func main() {
// Теперь мы можем передавать любые функции,
// которые соответствуют сигнатуре IntOperation
fmt.Println(applyOperation(10, increment)) // 11
fmt.Println(applyOperation(10, decrement)) // 9
}
Практическое применение
- Middleware в веб-серверах: Обработчики HTTP-запросов часто оборачиваются в цепочку функций (middleware) для логирования, аутентификации, сжатия и т.д.
- Callbacks: Для выполнения кода после завершения асинхронной операции.
- Реализация паттерна "Стратегия": Возможность подменять алгоритм выполнения на лету.
- Обработка данных: Написание универсальных функций для работы со слайсами (например,
filter
,map
), которые принимают функцию-предикат.