Einführung
Avariadic function ist eine Funktion, die null, einen oder mehrere Werte als einzelnes Argument akzeptiert. Variadische Funktionen sind zwar nicht üblich, können jedoch verwendet werden, um den Code übersichtlicher und lesbarer zu gestalten.
Variadische Funktionen sind häufiger als es scheint. Die häufigste ist diePrintln
-Funktion aus demfmt
-Paket.
func Println(a ...interface{}) (n int, err error)
Einfunction mit einem Parameter, dem eine Reihe von Ellipsen (...
) vorangestellt ist, wird als variadische Funktion betrachtet. Die Auslassungspunkte bedeuten, dass der bereitgestellte Parameter Null, Eins oder mehrere Werte sein kann. Für das Paketfmt.Println
wird angegeben, dass der Parametera
variadisch ist.
Erstellen wir ein Programm, das die Funktionfmt.Println
verwendet und null, einen oder mehrere Werte übergibt:
print.go
package main
import "fmt"
func main() {
fmt.Println()
fmt.Println("one")
fmt.Println("one", "two")
fmt.Println("one", "two", "three")
}
Wenn wir zum ersten Malfmt.Println
aufrufen, übergeben wir keine Argumente. Wenn wirfmt.Println
zum zweiten Mal aufrufen, übergeben wir nur ein einziges Argument mit dem Wertone
. Dann übergeben wirone
undtwo
und schließlichone
,two
undthree
.
Führen Sie das Programm mit dem folgenden Befehl aus:
go run print.go
Wir werden die folgende Ausgabe sehen:
Output
one
one two
one two three
Die erste Zeile der Ausgabe ist leer. Dies liegt daran, dass wir beim ersten Aufruf vonfmt.Println
keine Argumente übergeben haben. Beim zweiten Mal wurde der Wert vonone
gedruckt. Dannone
undtwo
und schließlichone
,two
undthree
.
Nachdem wir gesehen haben, wie man eine Variadic-Funktion aufruft, wollen wir uns ansehen, wie wir unsere eigene Variadic-Funktion definieren können.
Definieren einer variablen Funktion
Wir können eine variadische Funktion definieren, indem wir eine Ellipse (...
) vor dem Argument verwenden. Erstellen wir ein Programm, das Personen begrüßt, wenn ihre Namen an die Funktion gesendet werden:
hello.go
package main
import "fmt"
func main() {
sayHello()
sayHello("Sammy")
sayHello("Sammy", "Jessica", "Drew", "Jamie")
}
func sayHello(names ...string) {
for _, n := range names {
fmt.Printf("Hello %s\n", n)
}
}
Wir haben einesayHello
-Funktion erstellt, die nur einen einzigen Parameter namensnames
akzeptiert. Der Parameter ist variadisch, da vor dem Datentyp eine Ellipse (...
) steht:...string
. Dies teilt Go mit, dass die Funktion null, ein oder viele Argumente akzeptieren kann.
Die FunktionsayHello
empfängt den Parameternames
alsslice
. Da der Datentypstring
ist, kann der Parameternames
wie ein Stück Zeichenfolgen ([]string
) innerhalb des Funktionskörpers behandelt werden. Wir können eine Schleife mit dem Operatorrange
erstellen und durch das String-Slice iterieren.
Wenn wir das Programm ausführen, erhalten wir die folgende Ausgabe:
OutputHello Sammy
Hello Sammy
Hello Jessica
Hello Drew
Hello Jamie
Beachten Sie, dass beim ersten Aufruf vonsayHello
nichts gedruckt wurde. Dies liegt daran, dass der variadische Parameter ein leererslice
vonstring
war. Da wir das Slice durchlaufen, gibt es nichts zu durchlaufen, undfmt.Printf
wird niemals aufgerufen.
Ändern Sie das Programm, um festzustellen, dass keine Werte gesendet wurden:
hello.go
package main
import "fmt"
func main() {
sayHello()
sayHello("Sammy")
sayHello("Sammy", "Jessica", "Drew", "Jamie")
}
func sayHello(names ...string) {
if len(names) == 0 {
fmt.Println("nobody to greet")
return
}
for _, n := range names {
fmt.Printf("Hello %s\n", n)
}
}
Wenn Sie nunif
statement verwenden und keine Werte übergeben werden, beträgt die Länge vonnames
0
, und wir druckennobody to greet
aus:
Outputnobody to greet
Hello Sammy
Hello Sammy
Hello Jessica
Hello Drew
Hello Jamie
Die Verwendung eines variablen Parameters kann den Code lesbarer machen. Erstellen wir eine Funktion, die Wörter mit einem bestimmten Trennzeichen verbindet. Wir werden dieses Programm zunächst ohne eine Variadic-Funktion erstellen, um zu zeigen, wie es lauten würde:
join.go
package main
import "fmt"
func main() {
var line string
line = join(",", []string{"Sammy", "Jessica", "Drew", "Jamie"})
fmt.Println(line)
line = join(",", []string{"Sammy", "Jessica"})
fmt.Println(line)
line = join(",", []string{"Sammy"})
fmt.Println(line)
}
func join(del string, values []string) string {
var line string
for i, v := range values {
line = line + v
if i != len(values)-1 {
line = line + del
}
}
return line
}
In diesem Programm übergeben wir ein Komma (,
) als Trennzeichen an die Funktionjoin
. Dann übergeben wir eine Werteschicht, um sie zu verbinden. Hier ist die Ausgabe:
OutputSammy,Jessica,Drew,Jamie
Sammy,Jessica
Sammy
Da die Funktion einen String-String alsvalues
-Parameter verwendet, mussten wir alle unsere Wörter in einen Slice einschließen, als wir diejoin
-Funktion aufriefen. Dies kann das Lesen des Codes erschweren.
Schreiben wir nun die gleiche Funktion, verwenden jedoch eine andere Funktion:
join.go
package main
import "fmt"
func main() {
var line string
line = join(",", "Sammy", "Jessica", "Drew", "Jamie")
fmt.Println(line)
line = join(",", "Sammy", "Jessica")
fmt.Println(line)
line = join(",", "Sammy")
fmt.Println(line)
}
func join(del string, values ...string) string {
var line string
for i, v := range values {
line = line + v
if i != len(values)-1 {
line = line + del
}
}
return line
}
Wenn wir das Programm ausführen, können wir sehen, dass wir die gleiche Ausgabe wie das vorherige Programm erhalten:
OutputSammy,Jessica,Drew,Jamie
Sammy,Jessica
Sammy
Während beide Versionen derjoin
-Funktion programmgesteuert genau dasselbe tun, ist die variable Version der Funktion beim Aufrufen viel einfacher zu lesen.
Variadic Argument Order
Sie können nur einen variablen Parameter in einer Funktion haben, und es muss der letzte in der Funktion definierte Parameter sein. Das Definieren von Parametern in einer variablen Funktion in einer anderen Reihenfolge als dem letzten Parameter führt zu einem Kompilierungsfehler:
join.go
package main
import "fmt"
func main() {
var line string
line = join(",", "Sammy", "Jessica", "Drew", "Jamie")
fmt.Println(line)
line = join(",", "Sammy", "Jessica")
fmt.Println(line)
line = join(",", "Sammy")
fmt.Println(line)
}
func join(values ...string, del string) string {
var line string
for i, v := range values {
line = line + v
if i != len(values)-1 {
line = line + del
}
}
return line
}
Dieses Mal setzen wir den Parametervalues
zuerst in die Funktionjoin
. Das wird den folgenden Kompilierungsfehler verursachen:
Output./join_error.go:18:11: syntax error: cannot use ... with non-final parameter values
Bei der Definition einer variablen Funktion kann nur der letzte Parameter variabel sein.
Explodierende Argumente
Bisher haben wir gesehen, dass wir einer variadischen Funktion keinen, einen oder mehrere Werte übergeben können. Es wird jedoch Gelegenheiten geben, in denen wir einen Wertebereich haben und diese an eine variable Funktion senden möchten.
Schauen wir uns unserejoin
-Funktion aus dem letzten Abschnitt an, um zu sehen, was passiert:
join.go
package main
import "fmt"
func main() {
var line string
names := []string{"Sammy", "Jessica", "Drew", "Jamie"}
line = join(",", names)
fmt.Println(line)
}
func join(del string, values ...string) string {
var line string
for i, v := range values {
line = line + v
if i != len(values)-1 {
line = line + del
}
}
return line
}
Wenn wir dieses Programm ausführen, erhalten wir einen Kompilierungsfehler:
Output./join-error.go:10:14: cannot use names (type []string) as type string in argument to join
Obwohl die Variadic-Funktion den Parameter vonvalues ...string
in ein Slice von Strings[]string
konvertiert, können wir kein Slice von Strings als Argument übergeben. Dies liegt daran, dass der Compiler diskrete Argumente von Zeichenfolgen erwartet.
Um dies zu umgehen, können wirexplode ein Slice erstellen, indem wir es mit einer Reihe von Ellipsen (...
) versehen und in diskrete Argumente umwandeln, die an eine variable Funktion übergeben werden:
join.go
package main
import "fmt"
func main() {
var line string
names := []string{"Sammy", "Jessica", "Drew", "Jamie"}
line = join(",", names...)
fmt.Println(line)
}
func join(del string, values ...string) string {
var line string
for i, v := range values {
line = line + v
if i != len(values)-1 {
line = line + del
}
}
return line
}
Dieses Mal, als wir diejoin
-Funktion aufgerufen haben, haben wir dienames
-Schicht durch Anhängen von Ellipsen (...
) aufgelöst.
Dadurch kann das Programm nun wie erwartet ausgeführt werden:
OutputSammy,Jessica,Drew,Jamie
Es ist wichtig zu beachten, dass wir immer noch ein, ein oder mehrere Argumente sowie einen Teil, den wir explodieren, übergeben können. Hier ist der Code, der alle Variationen übergibt, die wir bisher gesehen haben:
join.go
package main
import "fmt"
func main() {
var line string
line = join(",", []string{"Sammy", "Jessica", "Drew", "Jamie"}...)
fmt.Println(line)
line = join(",", "Sammy", "Jessica", "Drew", "Jamie")
fmt.Println(line)
line = join(",", "Sammy", "Jessica")
fmt.Println(line)
line = join(",", "Sammy")
fmt.Println(line)
}
func join(del string, values ...string) string {
var line string
for i, v := range values {
line = line + v
if i != len(values)-1 {
line = line + del
}
}
return line
}
OutputSammy,Jessica,Drew,Jamie
Sammy,Jessica,Drew,Jamie
Sammy,Jessica
Sammy
Wir wissen jetzt, wie wir null, ein oder mehrere Argumente sowie einen Teil, den wir auflösen, an eine variable Funktion übergeben können.
Fazit
In diesem Tutorial haben wir gesehen, wie verschiedene Funktionen Ihren Code sauberer machen können. Sie müssen sie zwar nicht immer verwenden, finden sie jedoch möglicherweise nützlich:
-
Wenn Sie feststellen, dass Sie ein temporäres Segment erstellen, um es an eine Funktion zu übergeben.
-
Wenn die Anzahl der Eingabeparameter unbekannt ist oder beim Aufrufen variiert.
-
Um Ihren Code lesbarer zu machen.
Um mehr über das Erstellen und Aufrufen von Funktionen zu erfahren, können SieHow to Define and Call Functions in Go lesen.