Les fonctions d'ordre supérieur sont très utiles et peuvent vraiment améliorer le reusability
code. Cependant, l'une des plus grandes préoccupations liées à leur utilisation est l'efficacité. Les expressions Lambda sont compilées en classes (souvent des classes anonymes) et la création d'objets en Java est une opération lourde. Nous pouvons toujours utiliser des fonctions d'ordre supérieur de manière efficace, tout en conservant tous les avantages, en rendant les fonctions en ligne.
voici la fonction en ligne en image
Lorsqu'une fonction est marquée comme inline
, lors de la compilation du code, le compilateur remplacera tous les appels de fonction par le corps réel de la fonction. De plus, les expressions lambda fournies en tant qu'arguments sont remplacées par leur corps réel. Ils ne seront pas traités comme des fonctions, mais comme du code réel.
En bref: - Inline -> plutôt que d'être appelés, ils sont remplacés par le code du corps de la fonction au moment de la compilation ...
Dans Kotlin, utiliser une fonction comme paramètre d'une autre fonction (appelées fonctions d'ordre supérieur) semble plus naturel qu'en Java.
Cependant, l'utilisation de lambdas présente certains inconvénients. Puisqu'il s'agit de classes anonymes (et donc d'objets), elles ont besoin de mémoire (et peuvent même ajouter au nombre global de méthodes de votre application). Pour éviter cela, nous pouvons intégrer nos méthodes.
fun notInlined(getString: () -> String?) = println(getString())
inline fun inlined(getString: () -> String?) = println(getString())
De l'exemple ci-dessus : - Ces deux fonctions font exactement la même chose - imprimer le résultat de la fonction getString. L'un est en ligne et l'autre ne l'est pas.
Si vous vérifiez le code java décompilé, vous verrez que les méthodes sont complètement identiques. C'est parce que le mot clé en ligne est une instruction au compilateur pour copier le code dans le site d'appel.
Cependant, si nous passons un type de fonction à une autre fonction comme ci-dessous:
//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)
/*...*/
}
Pour résoudre cela, nous pouvons réécrire notre fonction comme ci-dessous:
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)
/*...*/}
Supposons que nous ayons une fonction d'ordre supérieur comme ci-dessous:
inline fun Int.doSomething(y: Int, noinline ftOne: Int.(Int) -> Int) {
//passing a function type to another function
val funOne = someFunction(ftOne)
/*...*/}
Ici, le compilateur nous dira de ne pas utiliser le mot clé inline lorsqu'il n'y a qu'un seul paramètre lambda et que nous le passons à une autre fonction. Ainsi, nous pouvons réécrire la fonction ci-dessus comme ci-dessous:
fun Int.doSomething(y: Int, ftOne: Int.(Int) -> Int) {
//passing a function type to another function
val funOne = someFunction(ftOne)
/*...*/
}
Remarque : -nous avons également dû supprimer le mot-clé noinline car il ne peut être utilisé que pour les fonctions en ligne!
Supposons que nous ayons une fonction comme celle-ci ->
fun intercept() {
// ...
val start = SystemClock.elapsedRealtime()
val result = doSomethingWeWantToMeasure()
val duration = SystemClock.elapsedRealtime() - start
log(duration)
// ...}
Cela fonctionne bien, mais le cœur de la logique de la fonction est pollué par le code de mesure, ce qui rend plus difficile pour vos collègues de travailler sur ce qui se passe. :)
Voici comment une fonction en ligne peut aider ce code:
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
}
Maintenant, je peux me concentrer sur la lecture de l'intention principale de la fonction intercept () sans sauter des lignes de code de mesure. Nous bénéficions également de la possibilité de réutiliser ce code dans d'autres endroits où nous voulons
inline vous permet d'appeler une fonction avec un argument lambda dans une fermeture ({...}) plutôt que de passer la mesure lambda like (myLamda)