Funkcje variadic w Go pozwalają na przyjmowanie zmiennej liczby argumentów jednego typu dzięki składni z wielokropkiem .... Na przykład:
func sum(nums ...int) int { total := 0 for _, num := range nums { total += num } return total }
Taką funkcję można wywołać z dowolną liczbą argumentów:
result := sum(1, 2, 3, 4) // 10
Lub przekazać slice, używając składni ...:
numbers := []int{1,2,3} result := sum(numbers...) // 6
Zawiłości:
[]T). Oznacza to, że można przekazać już przygotowany slice...., funkcja oczekuje zwykłego parametru typu []T, a nie variadic.Jaki wynik da następujący kod i dlaczego?
func printInts(nums ...int) { fmt.Printf("%#v ", nums) } ints := []int{1, 2, 3} printInts(ints)
Wielu błędnie sądzi, że ten kod się skompiluje, ale w rzeczywistości spowoduje błąd kompilacji:
Błąd: nie można przekazać slice'a bez ... do parametru variadic.
Poprawnie:
printInts(ints...) // OK
Historia
W dużym projekcie funkcję logowania opisano jako func Log(msgs ...string). Przy przekazywaniu wcześniej przygotowanego slice'a stringów wywoływano po prostu Log(strings), co skutkowało nieprawidłowym wyjściem logu lub paniką podczas pracy. Przyczyna — brak ..., więc funkcja postrzegała jeden argument typu []string, a nie oddzielne stringi.
Historia
W jednej z funkcji pomocniczych wymagana była obróbka parametrów, wśród których był slice, oraz dodanie do niego większej liczby elementów wewnątrz. Oczekiwano, że ... tworzy kopię slice'a, a nie przekazuje referencję — jednak wewnątrz funkcji modyfikowano slice, co niespodziewanie wpływało na stronę wywołującą, zwłaszcza jeśli pierwotny slice był wielokrotnie używanym buforem.
Historia
Programista zaimplementował funkcje agregujące, używając parametru variadic, ale jeden z kolegów błędnie użył składni wywołania poprzez rzutowanie: sum(interface{}([]int)), co prowadziło do niejawnych błędów w czasie wykonania, podczas gdy poprawnie byłoby użyć jawnie sum(slice...). Nieznajomość niuansów powodowała nieoczywiste błędy podczas masowych refaktoryzacji.