Функции высшего порядка
Учимся писать функции, которые принимают и возвращают другие функции.
Функция высшего порядка — функция, которая принимает другую функцию как параметр и/или возвращает функцию.
Раз функции — это значения, их можно передавать в другие функции. Так появляются функции высшего порядка: они позволяют выносить общий «каркас» алгоритма, оставляя переменную часть на откуп вызывающему коду.
Функция как параметр
Тип параметра-функции записывают как (Тип) -> Тип. Внутри такую функцию просто вызывают.
fun applyTwice(x: Int, op: (Int) -> Int): Int {
return op(op(x))
}
fun main() {
println(applyTwice(3) { it + 1 }) // (3+1)+1
println(applyTwice(2) { it * it }) // (2*2)=4, затем 4*4
}Вывод:
5 16
Зачем это нужно
Функции высшего порядка убирают дублирование. Вместо десяти почти одинаковых функций пишут одну, в которую передают различающуюся логику. На этом построены map, filter и почти все операции над коллекциями.
fun main() {
val numbers = listOf(1, 2, 3, 4, 5)
val evens = numbers.filter { it % 2 == 0 }
val squares = numbers.map { it * it }
println(evens)
println(squares)
}Вывод:
[2, 4] [1, 4, 9, 16, 25]
Ссылки на функции
Передавать можно не только лямбду, но и ссылку на уже существующую функцию — через оператор ::.
fun isEven(n: Int) = n % 2 == 0
fun main() {
val numbers = listOf(1, 2, 3, 4)
println(numbers.filter(::isEven))
}Вывод:
[2, 4]
Как работает под капотом
Тип функции вроде (Int) -> Int — обычный тип в системе типов Kotlin. Компилятор проверяет, что переданная лямбда соответствует ожидаемому типу. Под капотом каждая лямбда становится объектом, реализующим специальный интерфейс функции, а её вызов — это вызов метода этого объекта. Поэтому функции высшего порядка не магия, а строго типизированный механизм.
Частые ошибки
- Неверный тип функции-параметра.
(Int) -> Intи(Int) -> Booleanнесовместимы. - Дублировать почти одинаковые функции. Часто их заменяет одна функция высшего порядка.
- Забывать
::для ссылки. Имя функции без::воспринимается как её вызов, а не как ссылка на неё.
Итог
- Функция высшего порядка принимает и/или возвращает функцию.
- Тип функции записывается как
(Тип) -> Тип. - На этом механизме построены
map,filterи другие операции над коллекциями. - Ссылку на готовую функцию передают через
::.