如果函數(shù)的最后一個(gè)參數(shù)是采用 ...type 的形式,那么這個(gè)函數(shù)就可以處理一個(gè)變長(zhǎng)的參數(shù),這個(gè)長(zhǎng)度可以為 0,這樣的函數(shù)稱(chēng)為變參函數(shù)。
func myFunc(a, b, arg ...int) {}
這個(gè)函數(shù)接受一個(gè)類(lèi)似某個(gè)類(lèi)型的 slice 的參數(shù)(詳見(jiàn)第 7 章),該參數(shù)可以通過(guò)第 5.4.4 節(jié)中提到的 for 循環(huán)結(jié)構(gòu)迭代。
示例函數(shù)和調(diào)用:
func Greeting(prefix string, who ...string)
Greeting("hello:", "Joe", "Anna", "Eileen")
在 Greeting 函數(shù)中,變量 who 的值為 []string{"Joe", "Anna", "Eileen"}。
如果參數(shù)被存儲(chǔ)在一個(gè) slice 類(lèi)型的變量 slice 中,則可以通過(guò) slice... 的形式來(lái)傳遞參數(shù),調(diào)用變參函數(shù)。
示例 6.7 varnumpar.go
package main
import "fmt"
func main() {
x := min(1, 3, 2, 0)
fmt.Printf("The minimum is: %d\n", x)
slice := []int{7,9,3,5,1}
x = min(slice...)
fmt.Printf("The minimum in the slice is: %d", x)
}
func min(s ...int) int {
if len(s)==0 {
return 0
}
min := s[0]
for _, v := range s {
if v < min {
min = v
}
}
return min
}
輸出:
The minimum is: 0
The minimum in the slice is: 1
練習(xí) 6.3 varargs.go
寫(xiě)一個(gè)函數(shù),該函數(shù)接受一個(gè)變長(zhǎng)參數(shù)并對(duì)每個(gè)元素進(jìn)行換行打印。
一個(gè)接受變長(zhǎng)參數(shù)的函數(shù)可以將這個(gè)參數(shù)作為其它函數(shù)的參數(shù)進(jìn)行傳遞:
func F1(s ...string) {
F2(s...)
F3(s)
}
func F2(s ...string) { }
func F3(s []string) { }
變長(zhǎng)參數(shù)可以作為對(duì)應(yīng)類(lèi)型的 slice 進(jìn)行二次傳遞。
但是如果變長(zhǎng)參數(shù)的類(lèi)型并不是都相同的呢?使用 5 個(gè)參數(shù)來(lái)進(jìn)行傳遞并不是很明智的選擇,有 2 種方案可以解決這個(gè)問(wèn)題:
使用結(jié)構(gòu)(詳見(jiàn)第 10 章):
定義一個(gè)結(jié)構(gòu)類(lèi)型,假設(shè)它叫 Options,用以存儲(chǔ)所有可能的參數(shù):
type Options struct {
par1 type1,
par2 type2,
...
}
函數(shù) F1 可以使用正常的參數(shù) a 和 b,以及一個(gè)沒(méi)有任何初始化的 Options 結(jié)構(gòu): F1(a, b, Options {})。如果需要對(duì)選項(xiàng)進(jìn)行初始化,則可以使用 F1(a, b, Options {par1:val1, par2:val2})。
使用空接口:
如果一個(gè)變長(zhǎng)參數(shù)的類(lèi)型沒(méi)有被指定,則可以使用默認(rèn)的空接口 interface{},這樣就可以接受任何類(lèi)型的參數(shù)(詳見(jiàn)第 11.9 節(jié))。該方案不僅可以用于長(zhǎng)度未知的參數(shù),還可以用于任何不確定類(lèi)型的參數(shù)。一般而言我們會(huì)使用一個(gè) for-range 循環(huán)以及 switch 結(jié)構(gòu)對(duì)每個(gè)參數(shù)的類(lèi)型進(jìn)行判斷:
func typecheck(..,..,values … interface{}) {
for _, value := range values {
switch v := value.(type) {
case int: …
case float: …
case string: …
case bool: …
default: …
}
}
}