Je souhaite avoir un bon exemple pour chaque fonction exécuter, laisser, appliquer, aussi, avec
J'ai lu cet article mais il manque toujours un exemple
Je souhaite avoir un bon exemple pour chaque fonction exécuter, laisser, appliquer, aussi, avec
J'ai lu cet article mais il manque toujours un exemple
Toutes ces fonctions sont utilisées pour changer la portée de la fonction courante / de la variable. Elles sont utilisées pour garder les choses qui vont ensemble à un seul endroit (principalement les initialisations).
Voici quelques exemples :
run
- renvoie tout ce que vous voulez et re-scope la variable sur laquelle il est utilisé pour this
val password: Password = PasswordGenerator().run {
seed = "someString"
hash = {s -> someHash(s)}
hashRepetitions = 1000
generate()
}
Le générateur de mot de passe est maintenant rescopé comme this
et nous pouvons donc définir seed
, hash
y hashRepetitions
sans utiliser de variable. generate()
retournera une instance de Password
.
apply
est similaire, mais il retournera this
:
val generator = PasswordGenerator().apply {
seed = "someString"
hash = {s -> someHash(s)}
hashRepetitions = 1000
}
val pasword = generator.generate()
C'est particulièrement utile pour remplacer le modèle Builder, et si vous souhaitez réutiliser certaines configurations.
let
- principalement utilisé pour éviter les vérifications de nullité, mais peut également être utilisé en remplacement de run
. La différence, c'est que this
sera toujours le même qu'avant et vous accédez à la variable re-scopée en utilisant it
:
val fruitBasket = ...
apple?.let {
println("adding a ${it.color} apple!")
fruitBasket.add(it)
}
Le code ci-dessus ajoutera la pomme au panier uniquement si elle n'est pas nulle. Notez également que it
est maintenant n'est plus facultatif de sorte que vous ne rencontrerez pas d'exception NullPointerException ici (c'est-à-dire que vous n'avez pas besoin d'utiliser ?.
pour accéder à ses attributs)
also
- utilisez-le quand vous voulez utiliser apply
mais ne veulent pas faire de l'ombre this
class FruitBasket {
private var weight = 0
fun addFrom(appleTree: AppleTree) {
val apple = appleTree.pick().also { apple ->
this.weight += apple.weight
add(apple)
}
...
}
...
fun add(fruit: Fruit) = ...
}
Utilisation de apply
ici serait l'ombre this
de sorte que this.weight
ferait référence à la pomme, et no au panier de fruits.
Note : J'ai pris sans vergogne les exemples de mon blog
Il y a quelques autres articles comme aquí y aquí qui valent le coup d'œil.
Je pense qu'il s'agit de savoir quand on a besoin d'un texte plus court et plus concis en quelques lignes, et d'éviter les branchements ou la vérification d'instructions conditionnelles (comme if not null, then do this).
J'adore ce tableau simple, je l'ai donc mis en lien ici. Vous pouvez le voir à partir de este comme écrit par Sebastiano Gottardo.
Veuillez également consulter le graphique qui accompagne mon explication ci-dessous.
Je pense qu'il s'agit d'un jeu de rôle à l'intérieur de votre bloc de code lorsque vous appelez ces fonctions + si vous voulez revenir (pour enchaîner les fonctions d'appel, ou mettre à la variable de résultat, etc).
Voici ce que je pense.
Voyons des exemples pour chacun d'entre eux ici
1.) myComputer.apply { }
signifie que vous voulez agir en tant qu'acteur principal (vous voulez penser que vous êtes l'ordinateur), et que vous voulez vous récupérer (ordinateur) afin de pouvoir faire
var crashedComputer = myComputer.apply {
// you're the computer, you yourself install the apps
// note: installFancyApps is one of methods of computer
installFancyApps()
}.crash()
Ouaip, il suffit d'installer soi-même les applications, de se planter, et de s'enregistrer comme référence pour permettre aux autres de voir et de faire quelque chose avec.
2.) myComputer.also {}
signifie que vous êtes complètement sûr que vous no son ordinateur, vous êtes un outsider qui veut en faire quelque chose, et qui veut aussi que l'ordinateur soit un résultat retourné.
var crashedComputer = myComputer.also {
// now your grandpa does something with it
myGrandpa.installVirusOn(it)
}.crash()
3.) with(myComputer) { }
signifie que vous êtes l'acteur principal (ordinateur), et que vous Ne le fais pas. vous voulez retrouver le résultat.
with(myComputer) {
// you're the computer, you yourself install the apps
installFancyApps()
}
4.) myComputer.run { }
signifie que vous êtes l'acteur principal (ordinateur), et que vous Ne le fais pas. vous voulez retrouver le résultat.
myComputer.run {
// you're the computer, you yourself install the apps
installFancyApps()
}
mais c'est différent de with { }
dans un sens très subtil que vous pouvez appeler en chaîne run { }
comme les suivantes
myComputer.run {
installFancyApps()
}.run {
// computer object isn't passed through here. So you cannot call installFancyApps() here again.
println("woop!")
}
Ceci est dû à run {}
est une fonction d'extension, mais with { }
ne l'est pas. Donc vous appelez run { }
y this
à l'intérieur du bloc de code sera répercutée sur le type d'objet de l'appelant. Vous pouvez voir este pour une excellente explication de la différence entre run {}
y with {}
.
5.) myComputer.let { }
signifie que vous êtes une personne extérieure qui regarde l'ordinateur, et qui veut faire quelque chose à ce sujet sans se soucier de l'instance de l'ordinateur qui vous sera retournée.
myComputer.let {
myGrandpa.installVirusOn(it)
}
J'ai tendance à regarder also
y let
comme quelque chose d'externe, d'extérieur. Chaque fois que vous dites ces deux mots, c'est comme si vous essayiez d'agir sur quelque chose. let
installer un virus sur cet ordinateur, et also
Crash it. Donc, cela résout la question de savoir si vous êtes un acteur ou non.
Pour la partie résultat, c'est clairement là. also
exprime que c'est aussi une autre chose, donc vous conservez toujours la disponibilité de l'objet lui-même. Il le renvoie donc comme résultat.
Tout le reste s'associe à this
. En outre, run/with
n'est clairement pas intéressé par le retour de l'objet-soi. Maintenant vous pouvez les différencier tous.
Je pense que parfois, lorsque nous nous éloignons des exemples 100% programmés/logiques, nous sommes mieux placés pour conceptualiser les choses. Mais ça dépend :)
Il existe 6 fonctions de cadrage différentes :
J'ai préparé une note visuelle comme celle ci-dessous pour montrer les différences :
data class Citizen(var name: String, var age: Int, var residence: String)
La décision dépend de vos besoins. Les cas d'utilisation des différentes fonctions se chevauchent, de sorte que vous pouvez choisir les fonctions en fonction des conventions spécifiques utilisées dans votre projet ou votre équipe.
Bien que les fonctions scope soient un moyen de rendre le code plus concis, évitez d'en abuser : cela peut diminuer la lisibilité de votre code et entraîner des erreurs. Évitez d'imbriquer les fonctions scope et faites attention lorsque vous les enchaînez : il est facile de se tromper sur l'objet contextuel actuel et la valeur de this ou it.
Voici un autre diagramme permettant de décider lequel utiliser à partir de https://medium.com/@elye.project/mastering-kotlin-standard-functions-run-with-let-also-and-apply-9cd334b0ef84
Certaines conventions sont les suivantes :
Utilisez également pour des actions supplémentaires qui ne modifient pas l'objet, comme la journalisation ou l'impression d'informations de débogage.
val numbers = mutableListOf("one", "two", "three")
numbers
.also { println("The list elements before adding new one: $it") }
.add("four")
Le cas commun de appliquer est la configuration de l'objet.
val adam = Person("Adam").apply {
age = 32
city = "London"
}
println(adam)
Si vous avez besoin d'ombres, utilisez exécuter
fun test() {
var mood = "I am sad"
run {
val mood = "I am happy"
println(mood) // I am happy
}
println(mood) // I am sad
}
Si vous avez besoin de retourner l'objet récepteur lui-même, utilisez appliquer o également
laisser, également, appliquer, prendreSi, prendreSans sont des fonctions d'extension en Kotlin.
Pour comprendre ces fonctions, vous devez comprendre Fonctions d'extension y Fonctions lambda en Kotlin.
Fonction d'extension :
En utilisant la fonction d'extension, nous pouvons créer une fonction pour une classe sans hériter d'une classe.
Kotlin, à l'instar de C# et Gosu, offre la possibilité d'étendre une classe avec de nouvelles fonctionnalités sans avoir à hériter de la classe ou à utiliser ou d'utiliser un modèle de conception tel qu'un décorateur. Cela se fait par le biais de déclarations spéciales spéciales appelées extensions. Kotlin prend en charge les fonctions d'extension et les propriétés d'extension.
Donc, pour trouver si seulement les nombres dans le String
vous pouvez créer une méthode comme ci-dessous sans hériter de la méthode String
classe.
fun String.isNumber(): Boolean = this.matches("[0-9]+".toRegex())
vous pouvez utiliser la méthode ci-dessus fonction d'extension comme ça,
val phoneNumber = "8899665544"
println(phoneNumber.isNumber)
qui est imprimé true
.
Fonctions lambda :
Les fonctions lambda sont comme les interfaces en Java. Mais en Kotlin, les fonctions lambda peuvent être passées en paramètre dans les fonctions.
Ejemplo:
fun String.isNumber(block: () -> Unit): Boolean {
return if (this.matches("[0-9]+".toRegex())) {
block()
true
} else false
}
Vous pouvez voir que le bloc est une fonction lambda et qu'il est passé en paramètre. Vous pouvez utiliser la fonction ci-dessus comme ceci,
val phoneNumber = "8899665544"
println(phoneNumber.isNumber {
println("Block executed")
})
La fonction ci-dessus s'imprimera comme ceci,
Block executed
true
J'espère que vous avez maintenant une idée des fonctions d'extension et des fonctions Lambda. Nous allons maintenant passer aux fonctions d'extension une par une.
let
public inline fun <T, R> T.let(block: (T) -> R): R = block(this)
Deux types T et R utilisés dans la fonction ci-dessus.
T.let
T
peut être n'importe quel objet comme la classe String. Vous pouvez donc invoquer cette fonction avec n'importe quel objet.
block: (T) -> R
Dans le paramètre de let, vous pouvez voir la fonction lambda ci-dessus. De plus, l'objet invoquant est passé comme un paramètre de la fonction. Vous pouvez donc utiliser l'objet de la classe invoquante à l'intérieur de la fonction, qui renvoie alors l'objet R
(un autre objet).
Ejemplo:
val phoneNumber = "8899665544"
val numberAndCount: Pair<Int, Int> = phoneNumber.let { it.toInt() to it.count() }
Dans l'exemple ci-dessus, nous prenons Chaîne de caractères comme paramètre de sa fonction lambda et il retourne Paire en retour.
De la même manière, d'autres fonctions d'extension fonctionnent.
également
public inline fun <T> T.also(block: (T) -> Unit): T { block(this); return this }
fonction d'extension also
prend la classe invoquée comme paramètre de la fonction lambda et ne retourne rien.
Ejemplo:
val phoneNumber = "8899665544"
phoneNumber.also { number ->
println(number.contains("8"))
println(number.length)
}
appliquer
public inline fun <T> T.apply(block: T.() -> Unit): T { block(); return this }
Idem, mais le même objet d'invocation est passé comme la fonction, de sorte que vous pouvez utiliser les fonctions et autres propriétés sans l'appeler ou le nom du paramètre.
Ejemplo:
val phoneNumber = "8899665544"
phoneNumber.apply {
println(contains("8"))
println(length)
}
Vous pouvez voir dans l'exemple ci-dessus les fonctions de la classe String directement invoquées à l'intérieur de la fonction lambda.
takeIf
public inline fun <T> T.takeIf(predicate: (T) -> Boolean): T? = if (predicate(this)) this else null
Ejemplo:
val phoneNumber = "8899665544"
val number = phoneNumber.takeIf { it.matches("[0-9]+".toRegex()) }
Dans l'exemple ci-dessus number
aura une chaîne de phoneNumber
seulement il correspond à la regex
. Sinon, ce sera null
.
takeUnless
public inline fun <T> T.takeUnless(predicate: (T) -> Boolean): T? = if (!predicate(this)) this else null
C'est l'inverse de takeIf.
Ejemplo:
val phoneNumber = "8899665544"
val number = phoneNumber.takeUnless { it.matches("[0-9]+".toRegex()) }
number
aura une chaîne de phoneNumber
seulement si elle ne correspond pas à la regex
. Sinon, ce sera null
.
Vous pouvez voir des réponses similaires qui sont utiles ici. différence entre kotlin also, apply, let, use, takeIf et takeUnless en Kotlin
Il y a une faute de frappe dans votre dernier exemple, vous vouliez probablement dire phoneNumber. takeUnless{}
au lieu de phoneNumber. takeIf{}
.
Selon mon expérience, puisque ces fonctions sont du sucre syntaxique en ligne sans différence de performance, vous devriez toujours choisir celle qui nécessite d'écrire le moins de code dans la lamda.
Pour ce faire, déterminez d'abord si vous voulez que la lambda renvoie son résultat (choisissez run
/ let
) ou l'objet lui-même (choisissez apply
/ also
) ; puis, dans la plupart des cas, lorsque la lambda est une expression unique, choisissez celles qui ont le même type de fonction de bloc que cette expression, car lorsqu'il s'agit d'une expression réceptrice, this
peut être omis, lorsqu'il s'agit d'une expression de paramètre, it
est plus courte que this
:
val a: Type = ...
fun Type.receiverFunction(...): ReturnType { ... }
a.run/*apply*/ { receiverFunction(...) } // shorter because "this" can be omitted
a.let/*also*/ { it.receiverFunction(...) } // longer
fun parameterFunction(parameter: Type, ...): ReturnType { ... }
a.run/*apply*/ { parameterFunction(this, ...) } // longer
a.let/*also*/ { parameterFunction(it, ...) } // shorter because "it" is shorter than "this"
Toutefois, lorsque le lambda est constitué d'un mélange de ces éléments, il vous appartient alors de choisir celui qui s'intègre le mieux au contexte ou avec lequel vous vous sentez le plus à l'aise.
Utilisez également ceux qui ont une fonction de bloc de paramètres lorsque la déconstruction est nécessaire :
val pair: Pair<TypeA, TypeB> = ...
pair.run/*apply*/ {
val (first, second) = this
...
} // longer
pair.let/*also*/ { (first, second) -> ... } // shorter
Voici une brève comparaison entre toutes ces fonctions, tirée du cours officiel Kotlin de JetBrains sur Coursera. Kotlin pour les développeurs Java :
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.
0 votes
Utilisez kotlinlang.org/docs/scope-functions.html#fonction-selection pour avoir un aperçu rapide du récepteur et de la valeur de retour.