Erweiterungsfunktionen
Angenommen, Sie entdecken eine Bibliothek, die fast alles tut, was Sie brauchen… fast. Wenn sie nur ein oder zwei zusätzliche Mitgliedsfunktionen hätte, würde sie Ihr Problem perfekt lösen.
Aber es ist nicht Ihr Code – entweder haben Sie keinen Zugriff auf den Quellcode oder Sie kontrollieren ihn nicht. Sie müssten Ihre Änderungen bei jeder neuen Version wiederholen.
Kotlin’s extension functions fügen bestehenden Klassen effektiv Mitgliedsfunktionen hinzu. Der Typ, den Sie erweitern, wird receiver genannt. Um eine Erweiterungsfunktion zu definieren, setzen Sie den Typ des Empfängers vor den Funktionsnamen:
fun ReceiverType.extensionFunction() { ... }
Dies fügt der String-Klasse zwei Erweiterungsfunktionen hinzu:
// ExtensionFunctions/Quoting.kt
package extensionfunctions
import atomictest.eq
fun String.singleQuote() = "'$this'"
fun String.doubleQuote() = "\"$this\""
fun main() {
"Hi".singleQuote() eq "'Hi'"
"Hi".doubleQuote() eq "\"Hi\""
}
Sie rufen Erweiterungsfunktionen auf, als ob sie Mitglieder der Klasse wären.
Um Erweiterungen aus einem anderen Paket zu verwenden, müssen Sie sie importieren:
// ExtensionFunctions/Quote.kt
package other
import atomictest.eq
import extensionfunctions.doubleQuote
import extensionfunctions.singleQuote
fun main() {
"Single".singleQuote() eq "'Single'"
"Double".doubleQuote() eq "\"Double\""
}
Sie können auf Mitgliederfunktionen oder andere Erweiterungen mit dem Schlüsselwort this zugreifen.
this kann auch weggelassen werden, ebenso wie es innerhalb einer Klasse weggelassen werden kann, sodass
Sie keine explizite Qualifizierung benötigen:
// ExtensionFunctions/StrangeQuote.kt
package extensionfunctions
import atomictest.eq
// Apply two sets of single quotes:
fun String.strangeQuote() =
this.singleQuote().singleQuote() // [1]
fun String.tooManyQuotes() =
doubleQuote().doubleQuote() // [2]
fun main() {
"Hi".strangeQuote() eq "''Hi''"
"Hi".tooManyQuotes() eq "\"\"Hi\"\""
}
-
[1]
thisbezieht sich auf denString-Empfänger. -
[2] Wir lassen das Empfängerobjekt (
this) beim ersten Aufruf der FunktiondoubleQuote()weg.
Die Erweiterung Ihrer eigenen Klassen kann manchmal zu einfacherer Code führen:
// ExtensionFunctions/BookExtensions.kt
package extensionfunctions
import atomictest.eq
class Book(val title: String)
fun Book.categorize(category: String) =
"""title: "$title", category: $category"""
fun main() {
Book("Dracula").categorize("Vampire") eq
"""title: "Dracula", category: Vampire"""
}
Innerhalb von categorize() greifen wir ohne explizite Qualifikation auf die title-Eigenschaft zu.
- -
Erweiterungsfunktionen können nur auf öffentliche Elemente des zu erweiternden Typs zugreifen. Daher können Erweiterungen dieselben Aktionen wie reguläre Funktionen ausführen. Sie können Book.categorize(String) als categorize(Book, String) umschreiben. Der einzige Grund für die Verwendung einer Erweiterungsfunktion ist die Syntax, aber dieser syntaktische Zucker ist mächtig. Für den aufrufenden Code sehen Erweiterungen genauso aus wie Mitgliedsfunktionen, und IDEs zeigen Erweiterungen an, wenn sie die Funktionen auflisten, die Sie für ein Objekt aufrufen können.
Übungen und Lösungen finden Sie unter www.AtomicKotlin.com.