Ich möchte ein gutes Beispiel für jeden Funktionslauf haben, lassen, auch anwenden, mit
Ich habe diesen Artikel gelesen, aber es fehlt mir noch ein Beispiel
Ich möchte ein gutes Beispiel für jeden Funktionslauf haben, lassen, auch anwenden, mit
Ich habe diesen Artikel gelesen, aber es fehlt mir noch ein Beispiel
Alle diese Funktionen dienen zum Umschalten des Umfangs der aktuellen Funktion / der Variablen. Sie werden verwendet, um Dinge, die zusammengehören, an einem Ort zusammenzuhalten (meistens Initialisierungen).
Hier sind einige Beispiele:
run
- gibt alles zurück, was Sie wollen, und überprüft die Variable, für die es verwendet wird, erneut this
val password: Password = PasswordGenerator().run {
seed = "someString"
hash = {s -> someHash(s)}
hashRepetitions = 1000
generate()
}
Der Passwort - Generator wird jetzt rescoped wie this
und wir können daher eingestellt seed
, hash
und hashRepetitions
ohne eine Variable.
generate()
gibt eine Instanz von zurück Password
.
apply
ist ähnlich, aber es wird zurückkehren this
:
val generator = PasswordGenerator().apply {
seed = "someString"
hash = {s -> someHash(s)}
hashRepetitions = 1000
}
val pasword = generator.generate()
Dies ist besonders nützlich als Ersatz für das Builder-Muster und wenn Sie bestimmte Konfigurationen wiederverwenden möchten.
let
- Wird meistens verwendet, um Nullprüfungen zu vermeiden, kann aber auch als Ersatz für verwendet werden run
. Der Unterschied besteht darin, dass dies this
immer noch derselbe wie zuvor ist und Sie auf die Variable mit neuem Gültigkeitsbereich zugreifen, indem Sie it
:
val fruitBasket = ...
apple?.let {
println("adding a ${it.color} apple!")
fruitBasket.add(it)
}
Mit dem obigen Code wird der Apfel nur dann in den Warenkorb gelegt, wenn er nicht null ist. Beachten Sie auch, dass dies it
jetzt nicht mehr optional ist, sodass Sie hier nicht auf eine NullPointerException stoßen (auch bekannt als "Sie müssen nicht verwenden, ?.
um auf die Attribute zuzugreifen").
also
- Verwenden Sie es, wenn Sie es verwenden möchten apply
, aber nicht beschatten möchtenthis
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) = ...
}
Die Verwendung apply
hier würde Schatten spenden this
, sodass sich this.weight
dies auf den Apfel und nicht auf den Obstkorb beziehen würde .
Hinweis: Ich habe die Beispiele schamlos aus meinem Blog übernommen
Es gibt noch ein paar Artikel wie hier , und hier lohnt es sich, einen Blick darauf zu werfen.
Ich denke, es liegt daran, wann Sie eine kürzere, präzisere innerhalb weniger Zeilen benötigen und um Verzweigungen oder die Überprüfung bedingter Anweisungen zu vermeiden (z. B. wenn nicht null, dann tun Sie dies).
Ich liebe dieses einfache Diagramm, deshalb habe ich es hier verlinkt. Sie können es daraus sehen, wie es von Sebastiano Gottardo geschrieben wurde.
Bitte schauen Sie sich auch die Tabelle an, die meiner Erklärung unten beigefügt ist.
Konzept
Oben ist was ich denke.
Konzeptbeispiel
Sehen wir uns hier Beispiele für alle an
1.)
myComputer.apply { }
bedeutet, dass Sie als Hauptdarsteller auftreten möchten (Sie möchten glauben, dass Sie ein Computer sind), und dass Sie sich selbst zurückhaben möchten (Computer), damit Sie dies tun könnenJa, Sie selbst installieren einfach die Apps, stürzen sich ab und speichern sich als Referenz, damit andere etwas damit sehen und tun können.
2.)
myComputer.also {}
bedeutet, dass Sie völlig sicher sind , dass Sie kein Computer sind, dass Sie ein Außenseiter sind, der etwas damit anfangen möchte, und dass es auch ein Computer als zurückgegebenes Ergebnis sein soll.3.)
with(myComputer) { }
bedeutet, dass Sie Hauptdarsteller (Computer) sind und sich dadurch nicht zurückhaben möchten.4.)
myComputer.run { }
bedeutet, dass Sie Hauptdarsteller (Computer) sind und sich dadurch nicht zurückhaben möchten.Aber es unterscheidet sich
with { }
in einem sehr subtilen Sinne davon, dass Sie Anruferun { }
wie folgt verketten könnenDies liegt an der
run {}
Erweiterungsfunktion, ist es aberwith { }
nicht. Sie rufen also aufrun { }
undthis
innerhalb des Codeblocks wird der Objekttyp des Aufrufers angezeigt. Sie können dies für eine hervorragende Erklärung für den Unterschied zwischenrun {}
und sehenwith {}
.5.)
myComputer.let { }
bedeutet, dass Sie ein Außenseiter sind, der sich den Computer ansieht und etwas dagegen unternehmen möchte, ohne darauf zu achten, dass die Computerinstanz wieder an Sie zurückgegeben wird.Die Art, es zu betrachten
Ich neige dazu, zu betrachten
also
undlet
als etwas , das außerhalb extern ist. Wann immer Sie diese beiden Wörter sagen, ist es, als würden Sie versuchen, auf etwas zu reagieren.let
Installieren Sie den Virus auf diesem Computer undalso
stürzen Sie ihn ab. Das hängt also davon ab, ob Sie Schauspieler sind oder nicht.Für den Ergebnisteil ist es klar da.
also
drückt aus, dass es auch eine andere Sache ist, so dass Sie immer noch die Verfügbarkeit des Objekts selbst behalten. Somit wird es als Ergebnis zurückgegeben.Alles andere ist damit verbunden
this
. Außerdemrun/with
interessiert es eindeutig nicht, Objekt-Selbst zurück zu geben. Jetzt können Sie alle unterscheiden.Ich denke manchmal, wenn wir uns von 100% programmier- / logikbasierten Beispielen entfernen, sind wir besser in der Lage, Dinge zu konzipieren. Aber das hängt richtig ab :)
quelle
Lassen Sie auch Apply, TakeIf, TakeUnless Erweiterungsfunktionen in Kotlin sein.
Um diese Funktion zu verstehen, müssen Sie die Erweiterungsfunktionen und Lambda-Funktionen in Kotlin verstehen .
Erweiterungsfunktion:
Durch die Verwendung der Erweiterungsfunktion können wir eine Funktion für eine Klasse erstellen, ohne eine Klasse zu erben.
Um herauszufinden, ob nur Zahlen in der enthalten sind
String
, können Sie eine Methode wie die folgende erstellen, ohne dieString
Klasse zu erben .Sie können die obige Erweiterungsfunktion wie folgt verwenden:
Das ist Drucke
true
.Lambda-Funktionen:
Lambda-Funktionen sind wie Interface in Java. In Kotlin können Lambda-Funktionen jedoch als Parameter in Funktionen übergeben werden.
Beispiel:
Sie sehen, der Block ist eine Lambda-Funktion und wird als Parameter übergeben. Sie können die obige Funktion wie folgt verwenden:
Die obige Funktion wird wie folgt gedruckt:
Ich hoffe, jetzt haben Sie eine Vorstellung von Erweiterungsfunktionen und Lambda-Funktionen. Jetzt können wir nacheinander zu den Erweiterungsfunktionen gehen.
Lassen
Zwei Typen T und R, die in der obigen Funktion verwendet werden.
T
kann ein beliebiges Objekt wie die String-Klasse sein. Sie können diese Funktion also mit beliebigen Objekten aufrufen.Im Parameter let sehen Sie die obige Lambda-Funktion. Außerdem wird das aufrufende Objekt als Parameter der Funktion übergeben. Sie können also das aufrufende Klassenobjekt innerhalb der Funktion verwenden. dann gibt es das
R
(ein anderes Objekt) zurück.Beispiel:
Im obigen Beispiel nimmt let String als Parameter seiner Lambda-Funktion und gibt im Gegenzug Pair zurück.
Auf die gleiche Weise funktionieren andere Erweiterungsfunktionen.
ebenfalls
Die Erweiterungsfunktion verwendet
also
die aufrufende Klasse als Lambda-Funktionsparameter und gibt nichts zurück.Beispiel:
anwenden
Wie auch, aber dasselbe aufrufende Objekt, das als Funktion übergeben wurde, sodass Sie die Funktionen und andere Eigenschaften verwenden können, ohne sie oder den Parameternamen aufzurufen.
Beispiel:
Im obigen Beispiel sehen Sie die Funktionen der String-Klasse, die direkt in der Lambda-Funktion aufgerufen werden.
takeIf
Beispiel:
Im obigen Beispiel
number
wird nur eine Zeichenfolge angezeigt, die mit derphoneNumber
übereinstimmtregex
. Sonst wird es seinnull
.takeUnless
Es ist das Gegenteil von takeIf.
Beispiel:
number
wird eine Zeichenfolge vonphoneNumber
nur haben, wenn nicht mit der übereinstimmtregex
. Sonst wird es seinnull
.Sie können ähnliche Antworten anzeigen, was hier nützlich ist. Unterschied zwischen kotlin auch, anwenden, lassen, verwenden, takeIf und takeUnless in Kotlin
quelle
phoneNumber. takeUnless{}
stattdessen gemeint habenphoneNumber. takeIf{}
.Nach meiner Erfahrung sollten Sie immer diejenige auswählen, bei der die geringste Menge an Code in das Lamda geschrieben werden muss, da es sich bei solchen Funktionen um syntaktischen Inline-Zucker ohne Leistungsunterschied handelt.
Bestimmen Sie dazu zunächst, ob das Lambda sein Ergebnis zurückgeben soll (wählen Sie
run
/let
) oder das Objekt selbst (wählen Sieapply
/also
); In den meisten Fällen, wenn das Lambda ein einzelner Ausdruck ist, wählen Sie diejenigen mit demselben Blockfunktionstyp wie dieser Ausdruck aus, da ein Empfängerausdruckthis
weggelassen werden kann und ein Parameterausdruckit
kürzer ist alsthis
:Wenn das Lambda jedoch aus einer Mischung von ihnen besteht, liegt es an Ihnen, dasjenige zu wählen, das besser in den Kontext passt oder mit dem Sie sich wohler fühlen.
Verwenden Sie auch diejenigen mit Parameterblockfunktion, wenn eine Dekonstruktion erforderlich ist:
Hier ist ein kurzer Vergleich all dieser Funktionen aus JetBrains offiziellem Kotlin-Kurs über Coursera Kotlin für Java-Entwickler :
quelle
Es gibt 6 verschiedene Scoping-Funktionen:
Ich habe eine visuelle Notiz wie folgt vorbereitet, um die Unterschiede zu zeigen:
Die Entscheidung hängt von Ihren Bedürfnissen ab. Die Anwendungsfälle verschiedener Funktionen überschneiden sich, sodass Sie die Funktionen basierend auf den spezifischen Konventionen auswählen können, die in Ihrem Projekt oder Team verwendet werden.
Obwohl die Bereichsfunktionen eine Möglichkeit sind, den Code präziser zu gestalten, vermeiden Sie eine Überbeanspruchung: Sie können die Lesbarkeit des Codes beeinträchtigen und zu Fehlern führen. Vermeiden Sie das Verschachteln von Bereichsfunktionen und seien Sie vorsichtig, wenn Sie sie verketten: Es ist leicht, sich über das aktuelle Kontextobjekt und den Wert dieses oder jenes zu verwirren.
Hier ist ein weiteres Diagramm für die Entscheidung, welches von https://medium.com/@elye.project/mastering-kotlin-standard-functions-run-with-let-also-and-apply-9cd334b0ef84 verwendet werden soll
Einige Konventionen lauten wie folgt:
Verwenden Sie diese Option auch für zusätzliche Aktionen, die das Objekt nicht ändern, z. B. zum Protokollieren oder Drucken von Debug-Informationen.
Der häufigste Fall für die Anwendung ist die Objektkonfiguration.
Wenn Sie Schatten benötigen, verwenden Sie run
Wenn Sie das Empfängerobjekt selbst zurückgeben müssen, verwenden Sie apply oder auch
quelle