À la première et à la deuxième question
Comment venir (2) ne compile pas mais (4) n'est?.. la différence entre noinline
et crossinline
2. inline fun test(crossinline f: () -> Unit) {
thread(block = f)
}
4. inline fun test(crossinline f: () -> Unit) {
thread { f() }
}
Les deux cas ont inline
modificateur demandant de l'inclure à la fois la fonction test
et son argument lambda f
. De kotlin de référence:
La ligne modificateur affecte à la fois la fonction elle-même et les lambdas
passé: tous ceux qui seront intégrées dans le site d'appel.
Ainsi, le compilateur est chargé de placer le code (inline) plutôt que de construire et de faire appel à une fonction d'objet pour f
. crossinline
modificateur est seulement pour inline choses: il dit seulement que le passé lambda (en f
paramètre) ne devrait pas avoir de non-local retourne (le "normal" inline lambdas peuvent avoir). crossinline
peut être considéré comme quelque chose comme ceci (instruction pour le compilateur ): "ne inline, mais il y a une restriction qu'il est la traversée de l'invocateur contexte et donc, assurez-vous que le lambda n'a pas non local retourne.
Sur une note de côté, thread
semble conceptuellement exemple illustratif de crossinline
parce que, évidemment, de retour de code (adoptée en f
) plus tard sur un autre thread ne peut pas avoir une incidence sur le retour d' test
, qui continue à exécuter dans le thread appelant indépendamment de ce qu'il a engendré (f
va à exécuter de façon indépendante)..
Dans le cas n ° 4, il y a un lambda (accolades), invoquant f()
. Dans le cas n ° 2, f
est directement transmise comme argument d' thread
Donc en #4, appelez - f()
peut être insérée et le compilateur peut garantir il n'y a pas de non-retour locale. D'élaborer, le compilateur remplacera f()
avec sa définition et que le code est "enveloppé" à l'intérieur de la enfermant lambda, en d'autres termes, { //code for f() }
est en quelque sorte un autre (wrapper) lambda et lui-même est encore passé comme une fonction de l'objet de référence (à l' thread
).
Dans le cas #2, l'erreur du compilateur simplement dit qu'il ne peut pas inline f
car il est passé comme une référence à un "inconnu" (non-inline) place. crossinline
devient hors de l'endroit et hors de propos dans ce cas, car il peut être appliqué que si f
ont été inline.
Pour résumer, cas 2 et 4 ne sont pas les mêmes en les comparant à l'exemple de la kotlin de référence (voir "Fonctions d'Ordre Supérieur et les Lambdas"): ci-dessous les invocations sont équivalentes, où les accolades (lambda expression) "remplacer" la fonction wrapper toBeSynchronized
//want to pass `sharedResource.operation()` to lock body
fun <T> lock(lock: Lock, body: () -> T): T {...}
//pass a function
fun toBeSynchronized() = sharedResource.operation()
val result = lock(lock, ::toBeSynchronized)
//or pass a lambda expression
val result = lock(lock, { sharedResource.operation() })
Cas n ° 2 et n ° 4 dans la question ne sont pas équivalentes car il n'y a pas de "wrapper", invoquant f
#2