Ce face Funcții de ordin superior
În Kotlin funcțiile sunt valori: le poți pune în variabile, le poți trimite ca argumente și le poți returna. O funcție care primește sau returnează o altă funcție se numește funcție de ordin superior. filter, map, forEach sau sortedBy din biblioteca standard sunt astfel de funcții.
Tipul unui parametru funcție se scrie (TipParametri) -> TipRezultat: (Int) -> Int, (String, Int) -> Boolean, () -> Unit. Poate fi și nullable: ((Int) -> Int)?, apelat cu f?.invoke(x).
Ca argument poți da o lambda sau o referință de funcție cu ::: lista.filter(::estePar). Referințele merg și pentru metode (String::uppercase) și constructori (::Produs).
Exemple
Exemplul 1: Funcție care primește o funcție
aplicaLaToate nu știe ce operație face; o primește ca parametru. Același cod calculează jumătate de preț, adaugă transportul sau rotunjește la zeci.
fun aplicaLaToate(preturi: List<Double>, operatie: (Double) -> Double): List<Double> {
val rezultat = mutableListOf<Double>()
for (p in preturi) rezultat.add(operatie(p))
return rezultat
}
fun main() {
val preturi = listOf(104.0, 247.0, 39.0)
println(aplicaLaToate(preturi) { it / 2 })
println(aplicaLaToate(preturi) { it + 15 })
println(aplicaLaToate(preturi) { Math.round(it / 10) * 10.0 })
}
Rezultat
[52.0, 123.5, 19.5]
[119.0, 262.0, 54.0]
[100.0, 250.0, 40.0]
Exemplul 2: Funcție care returnează o funcție
reducere creează și returnează o lambda care „ține minte” procentul primit.
fun reducere(procent: Int): (Double) -> Double = { pret -> pret * (100 - procent) / 100 }
fun main() {
val blackFriday = reducere(30)
val studenti = reducere(10)
println("Laptop: ${blackFriday(3000.0)} lei")
println("Abonament: ${studenti(50.0)} lei")
val oferte = listOf(reducere(5), reducere(15), reducere(50))
println(oferte.map { it(200.0) })
}
Rezultat
Laptop: 2100.0 lei
Abonament: 45.0 lei
[190.0, 170.0, 100.0]
Exemplul 3: Referințe de funcții cu ::
::estePar trimite funcția existentă în loc de o lambda. String::uppercase este o referință la o metodă.
fun estePar(n: Int) = n % 2 == 0
fun main() {
val numere = listOf(3, 8, 12, 7, 4)
println(numere.filter(::estePar))
val orase = listOf("iași", "cluj", "brașov")
println(orase.map(String::uppercase))
val verificare: (Int) -> Boolean = ::estePar
println("10 este par? ${verificare(10)}")
}
Rezultat
[8, 12, 4]
[IAȘI, CLUJ, BRAȘOV]
10 este par? true
Greșeli frecvente
- Scrierea tipului funcție fără paranteze la parametri:
Int -> Intnu este valid, se scrie(Int) -> Int. - Apelarea unei funcții nullable direct:
f(x)nu compilează dacăfare tipul((Int) -> Int)?. Foloseștef?.invoke(x). - Funcțiile de ordin superior creează un obiect pentru fiecare lambda. În bucle foarte dese, marchează funcția cu
inline, ca biblioteca standard.
Comenzi înrudite
lambda: 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.inline, noinline și crossinline: inline copiază corpul funcției și lambda-urile ei în locul apelului; noinline și crossinline controlează lambda-urile primite.fun: fun declară o funcție: un bloc de cod cu nume, care primește parametri și poate returna un rezultat.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.map: Creează o listă nouă în care fiecare element este rezultatul funcției aplicate elementului original.