Le funzioni di ordine superiore sono molto utili e possono davvero migliorare il reusability
codice. Tuttavia, una delle maggiori preoccupazioni riguardo al loro utilizzo è l'efficienza. Le espressioni Lambda vengono compilate in classi (spesso classi anonime) e la creazione di oggetti in Java è un'operazione pesante. Possiamo ancora utilizzare le funzioni di ordine superiore in modo efficace, mantenendo tutti i vantaggi, rendendo le funzioni in linea.
ecco che arriva la funzione inline nell'immagine
Quando una funzione è contrassegnata come inline
, durante la compilazione del codice il compilatore sostituirà tutte le chiamate di funzione con il corpo effettivo della funzione. Inoltre, le espressioni lambda fornite come argomenti vengono sostituite con il loro corpo effettivo. Non verranno trattati come funzioni, ma come codice effettivo.
In breve: - Inline -> invece di essere chiamati, vengono sostituiti dal codice del corpo della funzione in fase di compilazione ...
In Kotlin, l'utilizzo di una funzione come parametro di un'altra funzione (le cosiddette funzioni di ordine superiore) sembra più naturale che in Java.
Tuttavia, l'utilizzo di lambda presenta alcuni svantaggi. Poiché sono classi anonime (e quindi oggetti), hanno bisogno di memoria (e potrebbero anche aumentare il conteggio complessivo dei metodi della tua app). Per evitare ciò, possiamo integrare i nostri metodi.
fun notInlined(getString: () -> String?) = println(getString())
inline fun inlined(getString: () -> String?) = println(getString())
Dall'esempio precedente : - Queste due funzioni fanno esattamente la stessa cosa: stampano il risultato della funzione getString. Uno è inline e uno no.
Se controlli il codice java decompilato, vedrai che i metodi sono completamente identici. Questo perché la parola chiave inline è un'istruzione al compilatore per copiare il codice nel sito di chiamata.
Tuttavia, se stiamo passando qualsiasi tipo di funzione a un'altra funzione come di seguito:
//Compile time error… Illegal usage of inline function type ftOne...
inline fun Int.doSomething(y: Int, ftOne: Int.(Int) -> Int, ftTwo: (Int) -> Int) {
//passing a function type to another function
val funOne = someFunction(ftOne)
/*...*/
}
Per risolverlo, possiamo riscrivere la nostra funzione come di seguito:
inline fun Int.doSomething(y: Int, noinline ftOne: Int.(Int) -> Int, ftTwo: (Int) -> Int) {
//passing a function type to another function
val funOne = someFunction(ftOne)
/*...*/}
Supponiamo di avere una funzione di ordine superiore come di seguito:
inline fun Int.doSomething(y: Int, noinline ftOne: Int.(Int) -> Int) {
//passing a function type to another function
val funOne = someFunction(ftOne)
/*...*/}
Qui, il compilatore ci dirà di non usare la parola chiave inline quando c'è solo un parametro lambda e lo stiamo passando a un'altra funzione. Quindi, possiamo riscrivere la funzione sopra come di seguito:
fun Int.doSomething(y: Int, ftOne: Int.(Int) -> Int) {
//passing a function type to another function
val funOne = someFunction(ftOne)
/*...*/
}
Nota : -abbiamo dovuto rimuovere anche la parola chiave noinline perché può essere utilizzata solo per le funzioni inline!
Supponiamo di avere una funzione come questa ->
fun intercept() {
// ...
val start = SystemClock.elapsedRealtime()
val result = doSomethingWeWantToMeasure()
val duration = SystemClock.elapsedRealtime() - start
log(duration)
// ...}
Funziona bene, ma la carne della logica della funzione è inquinata dal codice di misurazione, rendendo più difficile per i tuoi colleghi lavorare su quello che sta succedendo. :)
Ecco come una funzione inline può aiutare questo codice:
fun intercept() {
// ...
val result = measure { doSomethingWeWantToMeasure() }
// ...
}
inline fun <T> measure(action: () -> T) {
val start = SystemClock.elapsedRealtime()
val result = action()
val duration = SystemClock.elapsedRealtime() - start
log(duration)
return result
}
Ora posso concentrarmi sulla lettura di quale sia l'intenzione principale della funzione intercept () senza saltare le righe del codice di misurazione. Beneficiamo anche dell'opzione di riutilizzare quel codice in altri posti dove vogliamo
inline ti permette di chiamare una funzione con un argomento lambda all'interno di una chiusura ({...}) invece di passare la misura lambda (myLamda)