Функции, лямбды и функции высшего порядка
Функции в Kotlin компактны: они поддерживают параметры по умолчанию, краткую запись через знак равенства, а лямбды и функции высшего порядка делают код выразительным без громоздких анонимных классов.
Суть: умение писать лаконичные функции и передавать поведение через лямбды — ключ к идиоматичному Kotlin и к пониманию того, как устроены коллекции и Compose.
Функция объявляется ключевым словом fun. Дальше идут имя, параметры с типами и, при необходимости, тип возвращаемого значения после двоеточия. Если функция короткая и возвращает одно выражение, её можно записать через знак равенства — без фигурных скобок и без return.
fun sum(a: Int, b: Int): Int {
return a + b
}
// то же самое в краткой форме (expression body)
fun sumShort(a: Int, b: Int) = a + b
println(sum(2, 3)) // 5
println(sumShort(2, 3)) // 5Параметры по умолчанию и именованные аргументы
В Java ради разных наборов параметров писали перегрузки. В Kotlin достаточно задать значение по умолчанию. А при вызове можно указывать аргументы по именам — это резко повышает читаемость, особенно когда параметров много.
fun greet(name: String, greeting: String = "Привет"): String {
return "$greeting, $name!"
}
println(greet("Аня")) // Привет, Аня!
println(greet("Аня", greeting = "Здравствуй")) // именованный аргументЛямбды и функции высшего порядка
Лямбда — это анонимная функция, записанная в фигурных скобках. Функция высшего порядка — это функция, которая принимает другую функцию параметром или возвращает её. Именно на этом построены все операции над коллекциями и весь декларативный стиль Compose.
// функция высшего порядка: принимает операцию как параметр
fun calculate(a: Int, b: Int, op: (Int, Int) -> Int): Int {
return op(a, b)
}
val res1 = calculate(4, 5) { x, y -> x + y } // лямбда сложения
val res2 = calculate(4, 5) { x, y -> x * y } // лямбда умножения
println(res1) // 9
println(res2) // 20Как работает под капотом
Тип функции записывается стрелкой: (Int, Int) -> Int означает «функция, принимающая два Int и возвращающая Int». Лямбда — это объект такого типа. Если лямбда — последний аргумент функции, её выносят за круглые скобки (trailing lambda) — отсюда привычный синтаксис list.filter { ... }. Если у лямбды один параметр, его можно не называть и обращаться к нему через неявное имя it.
Тип функции: (Int, Int) -> Int
^^^^^^^^ ^^^
параметры результат
Trailing lambda:
calculate(4, 5) { x, y -> x + y }
\_______________/
вынесена за скобкиЧастые ошибки
Забывать про it. В лямбде с одним параметром не обязательно писать { item -> item.length } — короче { it.length }. Но если лямбд вложено несколько, лучше назвать параметры явно, чтобы не запутаться.
Писать длинные лямбды. Если тело лямбды разрослось, вынесите логику в отдельную именованную функцию — читать станет легче.
Игнорировать параметры по умолчанию. Новички плодят перегрузки, хотя одно значение по умолчанию решает задачу элегантнее.
Best practices
- Короткие функции пишите через expression body со знаком равенства.
- Используйте параметры по умолчанию вместо множества перегрузок.
- Именованные аргументы — для вызовов с большим числом параметров.
- Лямбды держите короткими; сложную логику выносите в именованные функции.
Идею функции высшего порядка удобно увидеть на Python: функция принимает операцию параметром, как calculate в Kotlin. Запустите врезку.
# Аналог функции высшего порядка из Kotlin
def calculate(a, b, op):
return op(a, b)
print(calculate(4, 5, lambda x, y: x + y)) # 9
print(calculate(4, 5, lambda x, y: x * y)) # 20
print(calculate(10, 3, lambda x, y: x - y)) # 7Попробуй сам ▶ — передайте свою операцию (деление, остаток, максимум). В Kotlin это была бы лямбда { x, y -> ... }.
Закрепим главное
Закрепите идею функции как значения. В Kotlin функцию можно передать в другую функцию, вернуть из неё и хранить в переменной — ровно как число или строку. Это не академическая деталь, а рабочий инструмент: именно так устроены и операции над коллекциями (filter { ... }), и обработчики событий в Compose (onClick = { ... }). Освоив лямбды сейчас, вы заранее понимаете синтаксис, который встретите на каждом экране Android-приложения.
Второй ориентир — лаконичность через параметры по умолчанию и именованные аргументы. Они заменяют ворох перегрузок одной гибкой сигнатурой и делают вызовы самодокументируемыми: greet(name, greeting = "Здравствуй") читается без обращения к документации. Это особенно ценно в Compose, где у composable бывает много параметров, и именованные аргументы спасают от путаницы, какой из них за что отвечает.
Итог: функции — основной строительный блок, а параметры по умолчанию, именованные аргументы и лямбды делают их гибкими и компактными. Функции высшего порядка — это фундамент, на котором стоят и операции над коллекциями из следующего раздела, и весь Jetpack Compose.