Variadic-Funktionen in Go ermöglichen es, eine variable Anzahl von Argumenten desselben Typs durch die Syntax mit Auslassungszeichen ... zu akzeptieren. Zum Beispiel:
func sum(nums ...int) int { total := 0 for _, num := range nums { total += num } return total }
Eine solche Funktion kann mit beliebig vielen Argumenten aufgerufen werden:
result := sum(1, 2, 3, 4) // 10
Oder man kann ein Slice mit der Syntax ... übergeben:
numbers := []int{1,2,3} result := sum(numbers...) // 6
Feinheiten:
[]T). Das bedeutet, dass man bereits ein vorbereitetes Slice hinein übergeben kann.... übergeben wird, erwartet die Funktion einen normalen Parameter vom Typ []T und nicht variadic.Welches Ergebnis liefert der folgende Code und warum?
func printInts(nums ...int) { fmt.Printf("%#v\n", nums) } ints := []int{1, 2, 3} printInts(ints)
Viele glauben fälschlicherweise, dass dieser Code kompiliert, aber tatsächlich wird er einen Kompilierungsfehler verursachen:
Fehler: Es ist nicht möglich, ein Slice ohne ... an einem variadic Parameter zu übergeben.
Richtig:
printInts(ints...) // OK
Geschichte
In einem großen Projekt wurde die Logging-Funktion als func Log(msgs ...string) beschrieben. Bei der Übergabe eines bereits vorbereiteten Slices von Strings wurde einfach Log(strings) aufgerufen, was zu falschen Logausgaben oder Panic zur Laufzeit führte. Der Grund dafür war das Fehlen von ..., sodass die Funktion einen einzelnen Parameter vom Typ []string anstatt separater Strings verstand.
Geschichte
In einer der Hilfsfunktionen war es erforderlich, Parameter zu verarbeiten, darunter ein Slice, und weitere Elemente hinzuzufügen. Man erwartete, dass ... eine Kopie des Slices erstellt, anstatt einen Verweis zu übergeben – aber innerhalb der Funktion wurde das Slice verändert, was unerwartet Einfluss auf die aufrufende Seite hatte, insbesondere wenn das ursprüngliche Slice ein wiederverwendeter Puffer war.
Geschichte
Ein Entwickler implementierte Aggregationsfunktionen, indem er einen variadic Parameter verwendete, aber einer der Kollegen verwendete fälschlicherweise die Aufrufsyntax durch Casting: sum(interface{}([]int)), was zu offensichtlichen Laufzeitfehlern führte, während es korrekt gewesen wäre, explizit sum(slice...) zu verwenden. Unkenntnis der Nuancen führte zu unerwarteten Bugs bei umfangreichen Refactorings.