W Go funkcja może akceptować tylko argumenty typu określonego na liście parametrów w definicji funkcji. Wariadyczna funkcja języka parametrów nieco to komplikuje, ale działa zgodnie z dobrze zdefiniowanymi regułami.
Podpis funkcji dla fmt.Println
:
func Println(a ...interface{}) (n int, err error)
Zgodnie ze specyfikacją językową ,
Ostatni parametr przychodzący w sygnaturze funkcji może mieć typ poprzedzony przedrostkiem .... Funkcja z takim parametrem nazywana jest wariadyczną i może być wywoływana z zerem lub większą liczbą argumentów dla tego parametru.
Oznacza to, że możesz przekazać Println
listę argumentów interface{}
typu. Ponieważ wszystkie typy implementują pusty interfejs, możesz przekazać listę argumentów dowolnego typu, dzięki czemu możesz Println(1, "one", true)
na przykład wywołać bez błędu. Zobacz sekcję „Przekazywanie argumentów do ... parametrów” specyfikacji języka:
przekazana wartość to nowy wycinek typu [] T z nową tablicą bazową, której kolejne elementy są faktycznymi argumentami, z których wszystkie muszą być przypisane do T.
Część, która sprawia kłopoty, znajduje się zaraz po tej w specyfikacji:
Jeśli ostatni argument można przypisać do typu wycinka [] T, może zostać przekazany niezmieniony jako wartość parametru ... T, jeśli po argumencie występuje .... W tym przypadku nie jest tworzony nowy wycinek.
flag.Args()
jest typem []string
. Ponieważ T
w Println
to interface{}
, []T
to []interface{}
. Zatem pytanie sprowadza się do tego, czy wartość wycinka łańcucha można przypisać do zmiennej typu wycinka interfejsu. Możesz to łatwo sprawdzić w swoim kodzie go, próbując przypisać, na przykład:
s := []string{}
var i []interface{}
i = s
Jeśli spróbujesz takiego przypisania, kompilator wyświetli następujący komunikat o błędzie:
cannot use s (type []string) as type []interface {} in assignment
Dlatego nie możesz użyć wielokropka po kawałku łańcucha jako argumentu funkcji fmt.Println
. To nie jest błąd, działa zgodnie z przeznaczeniem.
Nadal istnieje wiele sposobów można drukować flag.Args()
z Println
takich jak
fmt.Println(flag.Args())
(który zostanie wyświetlony jako [elem0 elem1 ...]
, zgodnie z dokumentacją pakietu fmt )
lub
fmt.Println(strings.Join(flag.Args(), ` `)
(co spowoduje wyświetlenie elementów wycinka ciągu, każdy oddzielony pojedynczą spacją) , na przykład przy użyciu funkcji Join w pakiecie ciągów z separatorem ciągu.
go run test.go some test flags
) i wydawało się, że działa przy zmianieflags.Args()...
na justflag.Args()
(na wyjściu znajduje się znak[some test flags]
nowej linii; również wydawało się, że działa z rejestrowaniem rzeczywistych flag). Nie będę udawać, że rozumiem, dlaczego, a odpowiedź Stephena i tak jest o wiele bardziej pouczająca :)