Lambda: какво е, синтаксис и използване в Kotlin

Автор: IT Sectr Публикувано: 2026-06-23 Време за четене: 7 мин

Lambda — е анонимна функция, представена под формата на компактен израз { аргументи -> тяло }. В Kotlin ламбдите са основният начин за предаване на поведение на функции от по-висок ред (higher-order functions), осигурявайки лаконичен синтаксис без необходимост от деклариране на отделна функция. Според документацията на Kotlin (2026), над 70% от функциите от по-висок ред в типичните проекти се извикват с ламбди. Lambda позволява писане на код във функционален стил с минимален синтактичен шум.

Основни точки

  • Lambda — анонимна функция в синтаксис { args -> body }, без име
  • Неявно име it замества единствения аргумент на ламбдата, опростявайки записа
  • Trailing lambda — изнасяне на последната ламбда извън скобите на извикване за четимост
  • Залавяне (closure) — ламбдата може да достъпва променливи от външния обхват на видимост
  • Функционален тип (T) -> R определя сигнатурата на ламбдата и се проверява от компилатора

Какво е lambda?

Lambda (ламбда израз) — е анонимна функция, дефинирана като израз, а не декларация. Терминът произхожда от ламбда смятането на Алонзо Чърч (1936). В програмирането ламбдата представлява блок код, който може да бъде предаден като стойност, съхранен в променлива и извикан по-късно. В Kotlin ламбдата винаги е затворена във фигурни скоби { }, аргументите са отделени от тялото със стрелка ->.

Ламбдата се различава от обикновената функция по липсата на име и ключова дума fun. Това позволява деклариране на поведение директно на мястото на използване, без да се затрупва кода с допълнителни декларации. Компилаторът на Kotlin извежда типовете на аргументите от контекста, така че в много случаи типовете могат да бъдат пропуснати. Ламбдата е синтактична захар над функционалния тип (T) -> R: всяка ламбда има съответен функционален тип.

Основното приложение на ламбдите в Kotlin е предаването им на функции от по-висок ред (higher-order functions). Стандартната библиотека използва ламбди навсякъде: filter { it > 0 }, map { it.uppercase() }, forEach { println(it) }. Ламбдите се използват също за създаване на слушатели на събития, обратни извиквания, конфигуратори на обекти чрез apply и run, което прави кода по-декларативен в сравнение с анонимните класове.

Синтаксис на ламбда изразите в Kotlin

Пълната форма на ламбда израза в Kotlin: { аргументи -> тяло_на_ламбда }. Аргументите се изброяват със запетая, следвани от стрелка и тяло — един или повече израза. Ако тялото съдържа няколко реда, последният израз става връщаната стойност. Ако функцията приема ламбда като последен аргумент, тя може да бъде изнесена извън скобите на извикване.

kotlin
val sum: (Int, Int) -> Int = { a, b -> a + b }

// Типове, изведени от контекста
val sumShort = { a: Int, b: Int -> a + b }

// Извикване на ламбда
val result = sum(5, 3)  // 8
println(result)

Променливата sum е декларирана с изричен функционален тип (Int, Int) -> Int и инициализирана с ламбда { a, b -> a + b }. За sumShort типовете са посочени вътре в ламбдата, а типът на променливата е изведен. И двата варианта са еквивалентни. Извикването на ламбда не се различава от извикването на обикновена функция — използва се синтаксис sum(5, 3). Ламбда без аргументи се записва като { body }, с един аргумент — { it -> it * 2 } или просто { it * 2 }.

Неявно име it и пропускане на аргументи

Когато ламбдата приема точно един аргумент, Kotlin предоставя неявното име it. Това елиминира необходимостта от деклариране на аргумента от лявата страна. Програмистът пише само тялото на ламбдата, използвайки it за достъп до единствения параметър. Такъв синтаксис е особено удобен във вериги за обработка на колекции, където it обозначава текущия елемент.

kotlin
val numbers = listOf(1, 2, 3, 4, 5)

// Изрично име на параметър
val squaredExplicit = numbers.map { n -> n * n }

// Неявно it
val squared = numbers.map { it * it }

// Филтриране с it
val even = numbers.filter { it % 2 == 0 }

println(squared) // [1, 4, 9, 16, 25]

В примера map { it * it } се използва it вместо декларация n ->. Kotlin автоматично присвоява it за единствения параметър на ламбдата. Ако ламбдата приема два или повече аргумента, it не се създава — всички параметри трябва да бъдат декларирани изрично. За по-добра четимост на вложени ламбди се препоръчва да се дават на параметрите смислени имена, а it да се използва в кратки едноредови предикати.

Trailing lambda и многоредови ламбди

Trailing lambda (завършваща ламбда) — синтактична особеност на Kotlin, която позволява последният аргумент-ламбда да бъде поставен извън кръглите скоби на извикване на функцията. Това прави кода подобен на вградени езикови конструкции. Ако ламбдата е единственият аргумент, скобите могат да бъдат напълно пропуснати. Този подход се използва активно в стандартната библиотека и DSL.

kotlin
// Стандартно извикване
thread(block = {
    println("Здравей от нишка")
})

// Версия с trailing lambda
thread {
    println("Здравей от нишка")
}

// repeat с trailing lambda
repeat(3) { index ->
    println("Итерация $index")
}

// run с многоредова ламбда
val config = run {
    val host = "localhost"
    val port = 8080
    "$host:$port"
}

Функцията thread приема Runnable като последен аргумент. Благодарение на trailing lambda, ламбдата може да бъде предадена извън скобите, което визуално наподобява блок код. Функцията repeat приема брой итерации и ламбда с индекс. run — пример за функция от по-висок ред, където многоредова ламбда изчислява стойността, връщана от последния израз. Скобите около run() могат да бъдат пропуснати, ако ламбдата е единственият аргумент.

Залавяне на променливи (closure) в ламбди

Залавяне на променливи (closure) — способността на ламбдата да достъпва променливи, декларирани във външния обхват на видимост. В Kotlin ламбдата може да чете и променя var променливи, както и да чете val променливи от околния контекст. Заловените променливи се съхраняват заедно с ламбдата през целия ѝ жизнен цикъл, което позволява създаването на функции със състояние.

kotlin
fun makeCounter(): () -> Int {
    var count = 0
    return {
        count++  // брой залавяния
    }
}

fun main() {
    val counter = makeCounter()
    println(counter()) // 0
    println(counter()) // 1
    println(counter()) // 2
}

Функцията makeCounter декларира локална променлива count и връща ламбда { count++ }. Въпреки че makeCounter е приключила работата си, върнатата ламбда запазва референция към count чрез затваряне (closure). Всяко извикване на counter() увеличава и връща текущата стойност. Механизмът closure стои в основата на къринг, фабрики за функции и мемоизация. Важно е да се помни, че залавянето на променливи променливи може да доведе до неочаквано поведение при паралелно изпълнение.

Често задавани въпроси

Може ли ламбдата да има return?

Ламбда не поддържа безусловен return — return без етикет връща управлението на външната функция. За излизане от ламбда използвайте return@label, където label е името на функцията от по-висок ред, на която е предадена ламбдата.

Каква е разликата между ламбда и анонимна функция?

Анонимна функция се записва като fun(a: Int): Int { return a * 2 } и поддържа return без етикет. Ламбда { a -> a * 2 } е синтактично по-кратка, но изисква return@label за ранно излизане.

Как да предам ламбда като аргумент без стрелка?

Ако ламбдата не приема аргументи, стрелката се пропуска: { body() }. Ако приема един аргумент и не го използва, вместо стрелка се пише { _ -> body() } с долна черта за игнориране на параметъра.

Ламбдата винаги ли създава нов обект?

Да, всяка ламбда, предадена на non-inline функция, създава инстанция на анонимен клас. За inline функции ламбдата се вгражда на мястото на извикване без създаване на обект. Незалавящите (non-capturing) ламбди се кешират в singleton обекти.

Защо не може да се използва return директно в ламбда?

Return в Kotlin е оператор за преход, принадлежащ на най-близката функция с fun. Ламбдата не е функция (fun), а израз. Следователно return вътре в ламбда без етикет се счита за връщане от външната обхващаща функция.

Обобщение

  • Lambda — анонимна функция в синтаксис { args -> body }, предавана като стойност на функция от по-висок ред
  • Неявно име it замества единствения аргумент и прави кода по-компактен в кратки предикати
  • Trailing lambda изнася последната ламбда извън скобите на извикване за четене като блок код
  • Залавяне (closure) позволява на ламбдата да достъпва променливи от външния контекст след завършване на обхващащата функция
  • Функционален тип (T) -> R определя сигнатурата на ламбдата с проверка на етапа на компилация
  • Inline функции елиминират създаването на анонимни класове за ламбди, повишавайки производителността в цикли
  • Многоредови ламбди връщат стойността на последния израз, поддържайки сложни изчисления без деклариране на отделна функция

Ще разработим мобилно приложение под ключ

IT Sectr създава iOS и Android приложения за стартъпи и бизнеси от 2017 г. Ще ви консултираме и ще предложим най-доброто решение.

Обсъдете проекта

Прочетете също