Scope-Funktionen ("Bereichsfunktionen") in Kotlin sind Standardfunktionen (let, also, run, apply, with), die es ermöglichen, den Kontext der Ausführung eines Codeblocks für ein Objekt zu steuern. Sie unterscheiden sich:
it oder über this.| Funktion | this/it | Gibt zurück | Wofür? |
|---|---|---|---|
| let | it | Ergebnis | Verkettung von Operationen, Arbeit mit Nullable, Map |
| also | it | Objekt | Side-Effects, Logging, Debugging |
| run | this | Ergebnis | Berechnungen, Initialisierung mit Rückgabe |
| apply | this | Objekt | Objektkonfiguration, Builder |
| with | this | Ergebnis | Arbeit mit externen APIs, Objekt "außen" |
Beispiele:
let: praktisch, wenn das Objekt nullable ist:val str: String? = "Text" str?.let { println(it.length) }
apply: Objektkonfiguration:val paint = Paint().apply { color = Color.RED strokeWidth = 2f }
run: Ausführung auf dem Objekt, Rückgabe des Ergebnisses:val length = "abcde".run { length }
with: für die Arbeit mit einem externen Objekt:val sb = StringBuilder() with(sb) { append("Hallo, ") append("Welt!") toString() }
also: für Side-Effects (z.B. Logs):val list = mutableListOf(1, 2, 3) list.also { println("Vorher: $it") }.add(4)
it, es ist nicht sehr praktisch, Eigenschaften des Objekts zu ändern.this / it), nützlich für Builder.with ist eine normale Funktion, keine Extension.Was ist der Unterschied zwischen let und also?
Antwort:
it innerhalb des Blocks,let gibt das Ergebnis des Lambdas zurück, wird häufig für Transformationsverkettungen verwendet,also gibt das ursprüngliche Objekt zurück, wird für Nebeneffekte (Logging, Debugging) verwendet, um nicht in die Transformationskette einzugreifen.Beispiel:
val result = listOf(1).also { println(it) }.map { it * 2 } // Ergebnis — List<Int>
Geschichte
Ein Neuling verwendete let, um ein Objekt zu konfigurieren, und dachte, dass er seinen Zustand "in der Kette" ändern könne. Am Ende des Konfigurationsblocks erhielt er nicht das Objekt, sondern das Ergebnis des Lambdas (z.B. nichts), was die Verkettenstruktur des DSL störte.
Geschichte
Bei der Programmierung mit Nullable-Objekten verwendeten wir run anstelle von let, wobei wir den Unterschied im Rückgabewert nicht bemerkten. Infolgedessen unterschied sich das Ergebnis des Ausdrucks von dem, was erwartet wurde, null tauchte dort auf, wo es nicht sein sollte — die Logik der Anwendung brach zusammen.
Geschichte
In einem großen Builder verwendeten wir versehentlich with für interne Objekte, in der Annahme, dass es sich um das Extension-Muster handelte. Da with keine Extension-Funktion ist, funktionierte die Kette aus mehreren with-Blöcken nicht korrekt, interne Aufrufe vermischten sich und gingen über den aktuellen Objektkontext hinaus. Wir mussten die Hierarchie zur Objekterstellung vollständig neu schreiben.