162 votes

Quand utiliser une fonction inline en Kotlin ?

Je sais qu'une fonction inline peut améliorer les performances et faire grossir le code généré, mais je ne sais pas quand il est correct de l'utiliser.

lock(l) { foo() }

Au lieu de créer un objet fonction pour le paramètre et de générer un appel, le compilateur pourrait émettre le code suivant. ( Source : )

l.lock()
try {
  foo()
}
finally {
  l.unlock()
}

mais j'ai constaté qu'il n'y a pas d'objet fonction créé par kotlin pour une fonction non-inline. pourquoi ?

/**non-inline function**/
fun lock(lock: Lock, block: () -> Unit) {
    lock.lock();
    try {
        block();
    } finally {
        lock.unlock();
    }
}

8 votes

Il existe deux cas d'utilisation principaux pour cela, l'un concerne certains types de fonctions d'ordre supérieur, et l'autre les paramètres de type réifié. La documentation des fonctions en ligne couvre ces cas : kotlinlang.org/docs/reference/inline-functions.html

5 votes

@zsmb13 merci, monsieur. mais je ne comprends pas que : "Au lieu de créer un objet fonction pour le paramètre et de générer un appel, le compilateur pourrait émettre le code suivant".

5 votes

Je ne comprends pas non plus cet exemple.

4voto

Anthony Naddeo Points 327

Un cas simple où vous pouvez en avoir besoin est celui de la création d'une fonction utilitaire qui reçoit un bloc de suspension. Considérez ceci.

fun timer(block: () -> Unit) {
    // stuff
    block()
    //stuff
}

fun logic() { }

suspend fun asyncLogic() { }

fun main() {
    timer { logic() }

    // This is an error
    timer { asyncLogic() }
}

Dans ce cas, notre timer n'acceptera pas les fonctions de suspension. Pour résoudre ce problème, vous pourriez être tenté de le rendre suspensif également

suspend fun timer(block: suspend () -> Unit) {
    // stuff
    block()
    // stuff
}

Mais alors il ne peut être utilisé qu'à partir des coroutines/fonctions de suspension elles-mêmes. Vous finirez donc par créer une version asynchrone et une version non asynchrone de ces utilitaires. Le problème disparaît si vous le faites en ligne.

inline fun timer(block: () -> Unit) {
    // stuff
    block()
    // stuff
}

fun main() {
    // timer can be used from anywhere now
    timer { logic() }

    launch {
        timer { asyncLogic() }
    }
}

Voici un terrain de jeu kotlin avec l'état d'erreur. Faites le timer en ligne pour résoudre ce problème.

0voto

ferraro Points 164
fun higherOrder(lambda:():Unit){
  //invoking lambda
    lambda()
}

  //Normal function calling higher-order without inline
fun callingHigerOrder() {
    higherOrder()
  //Here an object will be created for the lambda inside the higher-order function 
}

  //Normal function calling higher-order with inline
fun callingHigerOrder() {
    higherOrder()
  //Here there will be no object created and the contents of the lambda will be called directly into this calling function. 
}

utiliser inline si vous voulez éviter la création d'objets du côté de l'appelant. Lorsque vous utilisez l'inline, comme nous l'avons compris, le bloc lambda sera la partie de la fonction appelante. S'il y a un appel de retour à l'intérieur du bloc lambda, alors toute la fonction appelante sera retournée, ce qui est appelé retour non-local. Pour éviter le retour non-local, utilisez le cross-inline avant le bloc lambda dans la fonction d'ordre supérieur.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X