lambda în Kotlin

Funcții și lambda Kotlin 1.0

O lambda este o funcție fără nume, scrisă între acolade, pe care o poți pune într-o variabilă sau trimite altei funcții.

Sintaxă
val f: (Int, Int) -> Int = { a, b -> a + b }
val g = { x: Int -> x * 2 }
lista.filter { it > 5 }          // un singur parametru: it
lista.map { nota -> nota + 1 }

Ce face lambda

O expresie lambda se scrie între acolade: { a: Int, b: Int -> a + b }. Înainte de -> sunt parametrii, după el este corpul. Ultima expresie din corp este rezultatul; nu se scrie return. Tipul unei lambda este un tip funcție, de exemplu (Int, Int) -> Int.

Dacă lambda are un singur parametru, poți să nu-l numești: se numește automat it. Dacă lambda este ultimul argument al unei funcții, se scrie după paranteze (trailing lambda): lista.filter { it > 5 }. Așa arată aproape tot codul cu colecții din Kotlin.

O lambda poate folosi și modifica variabile din jurul ei (closure). Pentru a ieși devreme dintr-o lambda folosești o etichetă: return@forEach sare la următorul element. Un return simplu ar ieși din funcția care o conține (doar la funcțiile inline).

Exemple

Exemplul 1: Lambda în variabile

aduna are tipul scris explicit; la dublu tipul parametrului este scris în lambda. Ultima expresie din descrie este rezultatul.

fun main() {
    val aduna: (Int, Int) -> Int = { a, b -> a + b }
    val dublu = { x: Int -> x * 2 }
    val descrie = { nota: Int ->
        val text = if (nota >= 5) "promovat" else "nepromovat"
        "Nota $nota: $text"
    }

    println(aduna(7, 5))
    println(dublu(21))
    println(descrie(9))
    println(descrie(4))
}

Rezultat

12
42
Nota 9: promovat
Nota 4: nepromovat

Exemplul 2: it și lambda după paranteze

Funcțiile de colecții primesc lambda ca ultim argument. it este elementul curent.

fun main() {
    val preturi = listOf(12.5, 99.0, 45.0, 150.0)

    val ieftine = preturi.filter { it < 50 }
    val cuTva = preturi.map { pret -> pret * 1.21 }
    val total = preturi.sumOf { it }

    println("Sub 50 lei: $ieftine")
    println("Cu TVA: ${cuTva.map { "%.2f".format(it) }}")
    println("Total: $total lei")
    println("Sortate descrescător: ${preturi.sortedByDescending { it }}")
}

Rezultat

Sub 50 lei: [12.5, 45.0]
Cu TVA: [15.13, 119.79, 54.45, 181.50]
Total: 306.5 lei
Sortate descrescător: [150.0, 99.0, 45.0, 12.5]

Exemplul 3: Closure și return@eticheta

Lambda modifică variabila suma din afara ei. return@forEach sare peste notele invalide, fără să oprească bucla.

fun main() {
    val note = listOf(9, -1, 7, 11, 10)
    var suma = 0
    var valide = 0

    note.forEach { nota ->
        if (nota !in 1..10) {
            println("Ignor nota $nota")
            return@forEach
        }
        suma += nota
        valide++
    }
    println("Media notelor valide: ${suma.toDouble() / valide}")
}

Rezultat

Ignor nota -1
Ignor nota 11
Media notelor valide: 8.666666666666666

Greșeli frecvente

  • Scrierea lui return valoare într-o lambda: rezultatul unei lambda este ultima expresie. Un return simplu încearcă să iasă din funcția exterioară (și nu compilează dacă funcția nu este inline).
  • Folosirea lui it în lambda imbricate: it se referă la lambda cea mai apropiată. Dă nume explicite parametrilor când ai mai multe niveluri.
  • Confuzia dintre { x -> x * 2 } (lambda) și { x * 2 } fără parametru declarat: în al doilea caz x trebuie să existe deja în jur.

Comenzi înrudite

  • Funcții de ordin superior: O funcție de ordin superior primește o funcție ca parametru sau returnează o funcție.
  • fun: fun declară o funcție: un bloc de cod cu nume, care primește parametri și poate returna un rezultat.
  • inline, noinline și crossinline: inline copiază corpul funcției și lambda-urile ei în locul apelului; noinline și crossinline controlează lambda-urile primite.
  • Funcții de extensie: O funcție de extensie adaugă o metodă nouă unui tip existent (String, Int, List), fără să modifici clasa.
  • Iterable.forEach: Execută o acțiune pentru fiecare element, în ordine; forEachIndexed primește și poziția.