Funktionen höherer Ordnung sind sehr hilfreich und können den reusability
Code wirklich verbessern . Eines der größten Probleme bei der Verwendung ist jedoch die Effizienz. Lambda-Ausdrücke werden zu Klassen kompiliert (häufig anonyme Klassen), und die Objekterstellung in Java ist eine schwere Operation. Wir können weiterhin Funktionen höherer Ordnung effektiv nutzen und dabei alle Vorteile beibehalten, indem wir Funktionen inline machen.
Hier kommt die Inline-Funktion ins Bild
Wenn eine Funktion als markiert ist inline
, ersetzt der Compiler während der Codekompilierung alle Funktionsaufrufe durch den eigentlichen Funktionskörper. Außerdem werden als Argumente bereitgestellte Lambda-Ausdrücke durch ihren tatsächlichen Körper ersetzt. Sie werden nicht als Funktionen behandelt, sondern als tatsächlicher Code.
Kurz gesagt: - Inline -> anstatt aufgerufen zu werden, werden sie beim Kompilieren durch den Body-Code der Funktion ersetzt ...
In Kotlin fühlt sich die Verwendung einer Funktion als Parameter einer anderen Funktion (sogenannte Funktionen höherer Ordnung) natürlicher an als in Java.
Die Verwendung von Lambdas hat jedoch einige Nachteile. Da es sich um anonyme Klassen (und damit um Objekte) handelt, benötigen sie Speicher (und können sogar die Gesamtanzahl der Methoden Ihrer App erhöhen). Um dies zu vermeiden, können wir unsere Methoden einbinden.
fun notInlined(getString: () -> String?) = println(getString())
inline fun inlined(getString: () -> String?) = println(getString())
Aus dem obigen Beispiel : - Diese beiden Funktionen machen genau dasselbe - Drucken des Ergebnisses der Funktion getString. Einer ist inline und einer nicht.
Wenn Sie den dekompilierten Java-Code überprüfen würden, würden Sie feststellen, dass die Methoden vollständig identisch sind. Dies liegt daran, dass das Inline-Schlüsselwort eine Anweisung an den Compiler ist, den Code in die Aufrufseite zu kopieren.
Wenn wir jedoch einen Funktionstyp wie folgt an eine andere Funktion übergeben:
//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)
/*...*/
}
Um dies zu lösen, können wir unsere Funktion wie folgt umschreiben:
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)
/*...*/}
Angenommen, wir haben eine Funktion höherer Ordnung wie folgt:
inline fun Int.doSomething(y: Int, noinline ftOne: Int.(Int) -> Int) {
//passing a function type to another function
val funOne = someFunction(ftOne)
/*...*/}
Hier weist uns der Compiler an, das Inline-Schlüsselwort nicht zu verwenden, wenn nur ein Lambda-Parameter vorhanden ist und wir es an eine andere Funktion übergeben. Wir können also die obige Funktion wie folgt umschreiben:
fun Int.doSomething(y: Int, ftOne: Int.(Int) -> Int) {
//passing a function type to another function
val funOne = someFunction(ftOne)
/*...*/
}
Hinweis : - Wir mussten auch das Schlüsselwort noinline entfernen, da es nur für Inline-Funktionen verwendet werden kann!
Angenommen, wir haben eine Funktion wie diese ->
fun intercept() {
// ...
val start = SystemClock.elapsedRealtime()
val result = doSomethingWeWantToMeasure()
val duration = SystemClock.elapsedRealtime() - start
log(duration)
// ...}
Dies funktioniert gut, aber das Fleisch der Funktionslogik ist mit Messcode verschmutzt, was es Ihren Kollegen erschwert, an den Vorgängen zu arbeiten. :) :)
So kann eine Inline-Funktion diesem Code helfen:
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
}
Jetzt kann ich mich darauf konzentrieren, die Hauptabsicht der Funktion intercept () zu lesen, ohne die Zeilen des Messcodes zu überspringen. Wir profitieren auch von der Möglichkeit, diesen Code an anderen Stellen wiederzuverwenden, an denen wir möchten
Inline können Sie eine Funktion mit einem Lambda-Argument innerhalb eines Abschlusses ({...}) aufrufen, anstatt das Lambda-ähnliche Maß (myLamda) zu übergeben.