Comment est-ce lié aux fonctions d'extension? Pourquoi with
une fonction , pas un mot clé?
Il semble n'y avoir aucune documentation explicite sur ce sujet, seulement l'hypothèse de connaissance en référence à des extensions .
Comment est-ce lié aux fonctions d'extension? Pourquoi with
une fonction , pas un mot clé?
Il semble n'y avoir aucune documentation explicite sur ce sujet, seulement l'hypothèse de connaissance en référence à des extensions .
Il est vrai qu'il semble y avoir peu de documentation existante pour le concept de récepteurs (seulement une petite remarque concernant les fonctions d'extension), ce qui est surprenant vu:
with
, qui a donné aucune connaissance des récepteurs pourrait ressembler à un mot-clé;Tous ces sujets ont de la documentation, mais rien ne va plus en profondeur sur les récepteurs.
D'abord:
Tout bloc de code dans Kotlin peut avoir un (ou même plusieurs) types de comme un récepteur, les fonctions et les propriétés du récepteur disponibles dans ce bloc de code sans qualifiying il.
Imaginez un bloc de code comme ceci:
{ toLong() }
N'a pas beaucoup de sens, pas vrai? En fait, l'attribution à un type de fonction de l' (Int) -> Long
- où Int
le (seul) paramètre et le type de retour est - Long
- serait à juste titre, d'une erreur de compilation. Vous pouvez résoudre ce problème simplement en qualifiant l'appel de la fonction avec l'implicite seul paramètre it
. Cependant, pour le DSL de construction, ce qui va causer un tas de questions:
html { it.body { // how to access extensions of html here? } ... }
it
des appels, en particulier pour les lambdas utilisation de leurs paramètres (bientôt récepteur) d'un lot.C'est là que les récepteurs entrent en jeu.
Par l'attribution de ce bloc de code d'une fonction d'un type qui a Int
comme un récepteur (et non comme un paramètre!), le code soudain compile:
val intToLong: Int.() -> Long = { toLong() }
Ce qui se passe ici?
Cette rubrique suppose familarity avec des types de fonction, mais une petite note de côté pour les récepteurs est nécessaire.
Des types de fonction peut également avoir un récepteur, en préfixant avec le type et d'un point. Exemples:
Int.() -> Long // taking an integer as receiver producing a long
String.(Long) -> String // taking a string as receiver and long as parameter producing a string
GUI.() -> Unit // taking an GUI and producing nothing
Ces types de fonctions ont leur liste de paramètres préfixé avec le type de récepteur.
Il est en fait incroyablement facile de comprendre comment les blocs de code avec les récepteurs sont traitées:
Imaginez que, semblables à des fonctions d'extension, le bloc de code est évalué à l'intérieur de la classe du type de récepteur. ce fait devient modifié par le type de récepteur.
Pour notre exemple précédent, val intToLong: Int.() -> Long = { toLong() }
, il entraîne effectivement dans le bloc de code en cours d'évaluation dans un contexte différent, comme s'il était placé dans une fonction à l'intérieur d' Int
. Voici un autre exemple d'utilisation de types fabriqués à la main qui démontre le mieux:
class Bar
class Foo {
fun transformToBar(): Bar = TODO()
}
val myBlockOfCodeWithReceiverFoo: (Foo).() -> Bar = { transformToBar() }
devient (dans l'esprit, pas de code sages - vous ne pouvez pas réellement étendre des classes sur la JVM):
class Bar
class Foo {
fun transformToBar(): Bar = TODO()
fun myBlockOfCode(): Bar { return transformToBar() }
}
val myBlockOfCodeWithReceiverFoo: (Foo) -> Bar = { it.myBlockOfCode() }
Remarquez comment, à l'intérieur d'une classe, nous n'avons pas besoin d'utiliser this
accès transformToBar
- la même chose se produit dans un bloc avec un récepteur.
Il se trouve que la documentation sur ce explique également comment utiliser un ultrapériphériques récepteur si le bloc de code a deux récepteurs, par l'intermédiaire d'un qualifié ce.
Oui. Un bloc de code peut avoir plusieurs récepteurs, mais actuellement, cela n'a pas d'expression dans le système de type. La seule façon d'obtenir ce par le biais de multiples fonctions d'ordre supérieur que de prendre un seul récepteur type de fonction. Exemple:
class Foo
class Bar
fun Foo.functionInFoo(): Unit = TODO()
fun Bar.functionInBar(): Unit = TODO()
inline fun higherOrderFunctionTakingFoo(body: (Foo).() -> Unit) = body(Foo())
inline fun higherOrderFunctionTakingBar(body: (Bar).() -> Unit) = body(Bar())
fun example() {
higherOrderFunctionTakingFoo {
higherOrderFunctionTakingBar {
functionInFoo()
functionInBar()
}
}
}
Notez que si cette caractéristique de la Kotlin langue semble inapproprié pour votre DSL, @DslMarker est votre ami!
Pourquoi toute cette affaire? Avec cette connaissance:
toLong()
dans une extension de la fonction d'un nombre, au lieu d'avoir pour référence le nombre en quelque sorte. Peut-être que votre fonction d'extension ne doit pas être une extension?
with
, une bibliothèque standard de la fonction et non un mot-clé, existe - la modification de la portée d'un bloc de code pour enregistrer sur devenus inutiles de frappe est si commun, la langue des designers de le mettre dans la bibliothèque standard. Kotlin soutient le concept de "fonction littéraux avec des récepteurs". Il permet l'accès visible sur les méthodes et les propriétés d'un récepteur d'un lambda dans son corps , sans autres qualificatifs. Ceci est très similaire à l'extension de fonctions dans lequel il est également possible d'accéder visible des membres de l'objet récepteur à l'intérieur de l'extension.
Un exemple simple, aussi l'une des plus grandes fonctions dans le Kotlin de la bibliothèque standard, est -apply
:
public inline fun <T> T.apply(block: T.() -> Unit): T { block(); return this }
Comme vous pouvez le voir, une telle fonction littérale avec récepteur est prise comme argument block
ici. Ce bloc est simplement exécuté et le récepteur (qui est une instance de l' T
) est retourné. Dans cette action se présente comme suit:
val foo: Bar = Bar().apply {
color = RED
text = "Foo"
}
Nous instancions un objet d' Bar
et appelez - apply
sur il. L'instance de Bar
devient le "récepteur". L' block
, passé comme un argument en {}
(expression lambda) n'a pas besoin d'utiliser d'autres qualificatifs pour accéder et modifier l'montré les propriétés visibles color
et text
.
Le concept de lambdas avec récepteur est aussi la caractéristique la plus importante pour l'écriture de DSLs avec Kotlin.
var greet: String.() -> Unit = { println("Hello $this") }
ceci définit une variable de type String.() -> Unit
, ce qui en dit long
String
est le récepteur () -> Unit
est le type de fonctionComme F. George mentionné ci-dessus, toutes les méthodes de ce récepteur peut être appelée dans le corps de la méthode.
Ainsi, dans notre exemple, this
est utilisée pour imprimer l' String
. La fonction peut être appelée par l'écriture...
greet("Fitzgerald") // result is "Hello Fitzgerald"
l'extrait de code ci-dessus a été prise à partir de Kotlin Littéraux de Fonction avec Récepteur – Introduction Rapide par Simon Wirtz.
En termes simples (sans mots ni complications supplémentaires), le "Récepteur" est le type à étendre dans la fonction d’extension ou le nom de la classe. En utilisant les exemples donnés dans les réponses ci-dessus
fun Foo.functionInFoo(): Unit = TODO()
Le type "Foo" est le "récepteur"
var greet: String.() -> Unit = { println("Hello $this") }
Le type "String" est le "récepteur"
Conseil supplémentaire: recherchez la classe avant l’arrêt complet (.) Dans la déclaration de plaisir
fun receiver_class.function_name() {
//...
}
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.