Что такое lambda-выражения в Kotlin?
Lambda-выражения в Kotlin — это анонимные функции, которые можно передавать как значения, сохранять в переменные, вызывать напрямую или передавать как аргументы в другие функции. Они являются частью функционального программирования и играют ключевую роль при работе с коллекциями, обработке событий, построении DSL и других сценариях.
Синтаксис lambda-выражения
Общий вид:
val lambdaName: Type = { parameters -> body }
Примеры:
val sum = { a: Int, b: Int -> a + b }
val greet = { println("Hello!") }
Lambda можно вызвать, как обычную функцию:
println(sum(3, 5)) // 8
greet() // Hello!
Тип lambda-выражения
Тип lambda зависит от количества параметров и возвращаемого значения. Kotlin использует функциональные интерфейсы вида () -> Unit, (Int) -> String, (String, Int) -> Boolean и т.д.
val multiply: (Int, Int) -> Int = { x, y -> x \* y }
val sayHi: () -> Unit = { println("Hi") }
Использование в функциях высшего порядка
Функции высшего порядка — это функции, принимающие другие функции в качестве параметров или возвращающие их. Lambda особенно часто используется в таких случаях:
fun operate(x: Int, y: Int, op: (Int, Int) -> Int): Int {
return op(x, y)
}
val result = operate(4, 5) { a, b -> a + b } // 9
Специальный параметр it
Если у lambda-выражения один параметр, его можно не объявлять явно — Kotlin использует неявное имя it.
listOf(1, 2, 3).forEach { println(it) }
В этом примере it — это текущий элемент списка.
Возврат значений из lambda
Последнее выражение в lambda — это возвращаемое значение:
val square = { x: Int -> x \* x }
println(square(4)) // 16
Оператор return в lambda по умолчанию возвращает из окружающей функции только при использовании inline, иначе запрещён.
Для явного возврата из lambda в сложных случаях используют метки:
fun test() {
listOf(1, 2, 3).forEach label@{
if (it == 2) return@label
println(it)
}
}
Сокращённый синтаксис
Многие стандартные функции (например, filter, map, forEach, let) принимают lambda как аргумент и позволяют писать компактный код:
val names = listOf("Alice", "Bob", "Charlie")
val longNames = names.filter { it.length > 3 }
Lambda как объект: Function интерфейсы
Lambda — это экземпляры интерфейсов FunctionN, где N — количество параметров.
Примеры:
-
{ -> ... } → Function0<R>
-
{ a -> ... } → Function1<T, R>
-
{ a, b -> ... } → Function2<T1, T2, R>
Lambda также можно передавать и возвращать как объекты:
fun makeMultiplier(factor: Int): (Int) -> Int {
return { it \* factor }
}
Замыкания (Closures)
Lambda в Kotlin замыкает (захватывает) переменные из внешнего контекста:
fun makeCounter(): () -> Int {
var count = 0
return {
count += 1
count
}
}
val counter = makeCounter()
println(counter()) // 1
println(counter()) // 2
count — это захваченная переменная, живущая внутри lambda.
Lambda как аргумент вне скобок
Если последним аргументом функции является lambda, её можно вынести за круглые скобки:
fun doWork(task: () -> Unit) {
task()
}
doWork {
println("Working…")
}
Если lambda — единственный аргумент, скобки можно опустить:
run {
println("Inside run block")
}
Анонимные функции (fun) vs lambda
Kotlin также позволяет определять анонимные функции с использованием ключевого слова fun. Это похоже на lambda, но с явным указанием возвращаемого типа и return.
val divide = fun(a: Int, b: Int): Int {
if (b == 0) return 0
return a / b
}
Ключевое отличие — поведение return: в анонимной функции return работает как ожидается, а в lambda может требовать метку или inline-контекст.
Примеры использования в стандартной библиотеке Kotlin
-
map, filter, fold, reduce, groupBy, sortedBy
-
let, apply, run, also, with
-
Обработка событий, DSL, builder-паттерны
Пример:
val result = listOf(1, 2, 3)
.map { it \* 2 }
.filter { it > 3 }
Lambda-выражения — фундаментальный инструмент в Kotlin, позволяющий писать краткий, выразительный и гибкий код. Их мощь особенно раскрывается при использовании коллекций, конструировании DSL, реализации паттернов и написании функций высшего порядка.