2013-09-22 14 views
9

Oto przykład problemu Mam:Go: funkcja varariadic i zbyt wiele argumentów?

package main 

import "fmt" 

func foo(a int, b ...int) { 
    fmt.Println(a,b) 
} 

func main() { 
    a := 0 
    aa := 1 
    b := []int{2,3,4} 
    foo(a, aa, b...) 
} 

Gdy uruchomię to pojawia się błąd too many arguments in call to foo. Sądzę, że mogłem zrozumieć, dlaczego tak się dzieje, ale nie jest dla mnie jasne, jak mogę obejść to bez konieczności tworzenia kopii b z dodatkowym gniazdem na początku dla aa (którego wolałbym nie robić, jak ten kod będzie działał dość często i z pewnym opóźnieniem jest b).

Moje pytanie brzmi: czy robię to źle? A jeśli nie, jaki byłby najskuteczniejszy sposób robienia tego, co próbuję zrobić?

(Nie mogę również zmienić podpisu foo).

Odpowiedz

10

W idź runtime o zmiennej liczbie argumentów funkcja jest implemented jakby to miało dodatkowy parametr plasterek na końcu zamiast zmiennej liczbie argumentów parametru.

Na przykład

func Foo(a int, b ...int) 
func FooImpl(a int, b []int) 

c := 10 
d := 20 

//This call 
Foo(5, c, d) 

// is implemented like this 
b := []int{c, d} 
FooImpl(5, b) 

teoretycznie przechodzi może obsłużyć przypadek, w którym część a o zmiennej liczbie argumentów argumenty są podawane bezpośrednio, a pozostałe są rozszerzone z tablicy/plaster. Ale nie byłoby to skuteczne.

//This call 
Foo(5, c, b...) 

// would be implemented like this. 
v := append([]int{c},b...) 
FooImpl(5, v) 

Możesz zobaczyć, że Go i tak utworzy kopię: b. The ethos of Go is to be as small as possible and yet still useful. Tak małe funkcje, takie jak ten, zostają porzucone. Możesz być w stanie argumentować za tym cukrem syntaktycznym, ponieważ można go wdrożyć nieco bardziej wydajnie niż proste podejście append.

Należy pamiętać, że expanding a slice with ... does not create a copy of the underlying array do użycia jako parametr. Parametr tylko aliasy zmiennej. Innymi słowy, jest naprawdę skuteczny.

+0

Zmienna "b" wygląda raczej na plasterek niż tablicę. – Eonil

+0

Dobry połów. Zbyt łatwo jest złamać zasadę: "Nie nazwiesz kawałka tablicą!" –

+0

Podczas rozwijania plasterka struktura slice jest oczywiście kopiowana, ale podstawowa tablica nie jest kopiowana. Żeby być dokładnym. – PickBoy

7

można zrobić coś takiego:

package main 

import "fmt" 

func foo(a int, b ...int) { 
    fmt.Println(a,b) 
} 

func main() { 
    a := 0 
    aa := 1 
    b := []int{2,3,4} 
    foo(a, append([]int{aa}, b...)...) 
} 

Kiedy spodziewa b ...int, trzeba zdać []int... lub int „s jako parametry. Nie nie można mieszać int i []int...

Powiązane problemy