Benannte & Standardargumente
Sie können während eines Funktionsaufrufs Argumentnamen angeben.
Benannte Argumente verbessern die Code-Lesbarkeit. Dies gilt besonders für lange und komplexe Argumentlisten – benannte Argumente können so klar sein, dass der Leser einen Funktionsaufruf verstehen kann, ohne die Dokumentation anzusehen.
In diesem Beispiel sind alle Parameter Int. Benannte Argumente verdeutlichen ihre
Bedeutung:
// NamedAndDefaultArgs/NamedArguments.kt
package color1
import atomictest.eq
fun color(red: Int, green: Int, blue: Int) =
"($red, $green, $blue)"
fun main() {
color(1, 2, 3) eq "(1, 2, 3)" // [1]
color(
red = 76, // [2]
green = 89,
blue = 0
) eq "(76, 89, 0)"
color(52, 34, blue = 0) eq // [3]
"(52, 34, 0)"
}
- [1] Dies sagt Ihnen nicht viel. Sie müssen die Dokumentation einsehen, um zu verstehen, was die Argumente bedeuten.
- [2] Die Bedeutung jedes Arguments ist klar.
- [3] Es ist nicht erforderlich, alle Argumente zu benennen.
Benannte Argumente ermöglichen es Ihnen, die Reihenfolge der Farben zu ändern. Hier geben wir blue zuerst an:
// NamedAndDefaultArgs/ArgumentOrder.kt
import color1.color
import atomictest.eq
fun main() {
color(blue = 0, red = 99, green = 52) eq
"(99, 52, 0)"
color(red = 255, 255, 0) eq
"(255, 255, 0)"
}
Sie können benannte und reguläre (positionale) Argumente mischen. Wenn Sie die Reihenfolge der Argumente ändern, sollten Sie benannte Argumente im gesamten Aufruf verwenden—nicht nur der Lesbarkeit halber, sondern oft muss der Compiler wissen, wo die Argumente sind.
Benannte Argumente sind noch nützlicher, wenn sie mit Standardargumenten kombiniert werden, die Standardwerte für Argumente sind, die in der Funktionsdefinition angegeben sind:
// NamedAndDefaultArgs/Color2.kt
package color2
import atomictest.eq
fun color(
red: Int = 0,
green: Int = 0,
blue: Int = 0,
) = "($red, $green, $blue)"
fun main() {
color(139) eq "(139, 0, 0)"
color(blue = 139) eq "(0, 0, 139)"
color(255, 165) eq "(255, 165, 0)"
color(red = 128, blue = 128) eq
"(128, 0, 128)"
}
Jedes Argument, das Sie nicht angeben, erhält seinen Standardwert. Daher müssen Sie nur die Argumente angeben, die von den Standardwerten abweichen. Wenn Sie eine lange Argumentliste haben, vereinfacht dies den resultierenden Code, was das Schreiben und—was noch wichtiger ist—das Lesen erleichtert.
Dieses Beispiel verwendet auch ein nachgestelltes Komma in der Definition von color(). Das nachgestellte Komma ist das zusätzliche Komma nach dem letzten Parameter (blue). Dies ist nützlich, wenn Ihre Parameter oder Werte über mehrere Zeilen geschrieben sind. Mit einem nachgestellten Komma können Sie neue Elemente hinzufügen und ihre Reihenfolge ändern, ohne Kommas hinzuzufügen oder zu entfernen.
Benannte und Standardargumente (sowie nachgestellte Kommas) funktionieren auch für Konstruktoren:
// NamedAndDefaultArgs/Color3.kt
package color3
import atomictest.eq
class Color(
val red: Int = 0,
val green: Int = 0,
val blue: Int = 0,
) {
override fun toString() =
"($red, $green, $blue)"
}
fun main() {
Color(red = 77).toString() eq "(77, 0, 0)"
}
joinToString() ist eine Standardbibliotheksfunktion, die Standardargumente verwendet. Sie kombiniert die Inhalte eines iterierbaren Objekts (einer Liste, Menge oder eines Bereichs) zu einem String. Sie können einen Trennzeichen, ein Präfixelement und ein Suffixelement angeben:
// NamedAndDefaultArgs/CreateString.kt
import atomictest.eq
fun main() {
val list = listOf(1, 2, 3,)
list.toString() eq "[1, 2, 3]"
list.joinToString() eq "1, 2, 3"
list.joinToString(prefix = "(",
postfix = ")") eq "(1, 2, 3)"
list.joinToString(separator = ":") eq
"1:2:3"
}
Der Standardwert von toString() für eine List gibt den Inhalt in eckigen Klammern zurück, was möglicherweise nicht das ist, was Sie wollen. Die Standardwerte für die Parameter von joinToString() sind ein Komma für separator und leere Strings für prefix und postfix. Im obigen Beispiel verwenden wir benannte und Standardargumente, um nur die Argumente zu spezifizieren, die wir ändern möchten.
Der Initialisierer für list beinhaltet ein abschließendes Komma. Normalerweise verwenden Sie ein abschließendes Komma nur, wenn jedes Element in einer eigenen Zeile steht.
Wenn Sie ein Objekt als Standardargument verwenden, wird bei jedem Aufruf eine neue Instanz dieses Objekts erstellt:
Wenn Sie eine Objektinstanz als Standardargument übergeben (da innerhalb von g() im folgenden Beispiel), wird dieselbe Instanz für jeden Aufruf von g() verwendet. Wenn Sie die Syntax für einen Konstruktoraufruf übergeben (DefaultArg() innerhalb von h()), wird dieser Konstruktor jedes Mal aufgerufen, wenn Sie h() aufrufen:
// NamedAndDefaultArgs/Evaluation.kt
package namedanddefault
class DefaultArg
val da = DefaultArg()
fun g(d: DefaultArg = da) = println(d)
fun h(d: DefaultArg = DefaultArg()) =
println(d)
fun main() {
g()
g()
h()
h()
}
/* Sample output:
namedanddefault.DefaultArg@7440e464
namedanddefault.DefaultArg@7440e464
namedanddefault.DefaultArg@49476842
namedanddefault.DefaultArg@78308db1
*/
Die Ausgabe der beiden g() Aufrufe zeigt identische Objektadressen. Bei den beiden
Aufrufen von h() sind die Adressen der DefaultArg Objekte unterschiedlich, was zeigt,
dass es zwei verschiedene Objekte gibt.
Geben Sie Argumentnamen an, wenn sie die Lesbarkeit verbessern. Vergleichen Sie die folgenden beiden
Aufrufe von joinToString():
// NamedAndDefaultArgs/CreateString2.kt
import atomictest.eq
fun main() {
val list = listOf(1, 2, 3)
list.joinToString(". ", "", "!") eq
"1. 2. 3!"
list.joinToString(separator = ". ",
postfix = "!") eq "1. 2. 3!"
}
Es ist schwer zu erraten, ob ". " oder "" ein Trennzeichen ist, es sei denn, man merkt sich die Reihenfolge der Parameter, was unpraktisch ist.
Ein weiteres Beispiel für Standardargumente ist die trimMargin()-Funktion der Standardbibliothek, die mehrzeilige Strings formatiert. Sie verwendet einen Randpräfix-String, um den Anfang jeder Zeile festzulegen. trimMargin() entfernt führende Leerzeichen, gefolgt von dem Randpräfix, aus jeder Zeile des Quell-String. Es entfernt die erste und letzte Zeile, wenn sie leer sind:
// NamedAndDefaultArgs/TrimMargin.kt
import atomictest.eq
fun main() {
val poem = """
|->Last night I saw upon the stair
|->A little man who wasn't there
|->He wasn't there again today
|->Oh, how I wish he'd go away."""
poem.trimMargin() eq
"""->Last night I saw upon the stair
->A little man who wasn't there
->He wasn't there again today
->Oh, how I wish he'd go away."""
poem.trimMargin(marginPrefix = "|->") eq
"""Last night I saw upon the stair
A little man who wasn't there
He wasn't there again today
Oh, how I wish he'd go away."""
}
Das | (“Pipe”) ist das Standardargument für das Randpräfix, und Sie können es durch einen String Ihrer Wahl ersetzen.
Übungen und Lösungen finden Sie auf www.AtomicKotlin.com.