Go'da, bir işlev yalnızca işlev tanımındaki parametre listesinde belirtilen türlerin bağımsız değişkenlerini kabul edebilir. Değişken parametre dili özelliği bunu biraz karmaşıklaştırır, ancak iyi tanımlanmış kuralları izler.
İşlev imzası fmt.Println
şudur:
func Println(a ...interface{}) (n int, err error)
Başına dil specifiction ,
Bir işlev imzasındaki son gelen parametrenin ön ekli bir türü olabilir. Böyle bir parametreye sahip bir işlev, variadic olarak adlandırılır ve bu parametre için sıfır veya daha fazla argümanla çağrılabilir.
Bu Println
, interface{}
türdeki argümanların bir listesini iletebileceğiniz anlamına gelir . Tüm türler boş arabirimi uyguladığından, herhangi bir türden bağımsız değişkenlerin bir listesini iletebilirsiniz; bu, Println(1, "one", true)
örneğin, hatasız bir şekilde arama yapabilirsiniz . Bkz "için ... parametrelerin argümanları iletme" bölümüne dil şartnamenin:
aktarılan değer, [] T türünün yeni bir dilimidir ve ardışık öğeleri gerçek bağımsız değişkenlerdir ve tümü T'ye atanabilir olmalıdır.
Size sorun çıkaran kısım, şartnamede hemen ardından:
Son bağımsız değişken bir dilim türüne [] T atanabilirse, bağımsız değişkenden sonra .... gelirse, bir ... T parametresinin değeri olarak değiştirilmeden geçirilebilir. Bu durumda yeni dilim oluşturulmaz.
flag.Args()
tipidir []string
. Beri T
içinde Println
olduğu interface{}
, []T
olduğunu []interface{}
. Dolayısıyla soru, bir dizi dilim değerinin arabirim dilim türündeki bir değişkene atanabilir olup olmadığına bağlıdır. Bunu go kodunuzda bir atamayı deneyerek kolayca test edebilirsiniz, örneğin:
s := []string{}
var i []interface{}
i = s
Böyle bir atamayı denerseniz, derleyici şu hata mesajını verecektir:
cannot use s (type []string) as type []interface {} in assignment
İşte bu yüzden bir dize diliminden sonraki üç noktayı argüman olarak kullanamazsınız fmt.Println
. Bu bir hata değil, amaçlandığı gibi çalışıyor.
Yazdırmak yolları hala çok var flag.Args()
olan Println
gibi,
fmt.Println(flag.Args())
( fmt paket dokümantasyonuna[elem0 elem1 ...]
göre çıktı olarak verilir )
veya
fmt.Println(strings.Join(flag.Args(), ` `)
(bu, her biri tek bir boşlukla ayrılmış dize dilim öğelerini çıkarır), örneğin bir dize ayırıcı ile dizeler paketindeki Join işlevini kullanarak .
go run test.go some test flags
) veflags.Args()...
sadece değişirken işe yarıyor gibiydiflag.Args()
(çıktı[some test flags]
, ardından satırsonu; ayrıca gerçek bayrakların kaydedilmesiyle çalışıyor gibiydi). Nedenini anlıyormuş gibi yapmayacağım ve Stephen'ın cevabı zaten çok daha bilgilendirici :)