參數數量可變的函數稱為為可變參數函數。典型的例子就是fmt.Printf和類似函數。Printf首先接收一個的必備參數,之后接收任意個數的后續參數。
在聲明可變參數函數時,需要在參數列表的最后一個參數類型之前加上省略符號“...”,這表示該函數會接收任意數量的該類型參數。
gopl.io/ch5/sum
func sum(vals...int) int { total := 0 for _, val := range vals { total += val } return total }
sum函數返回任意個int型參數的和。在函數體中,vals被看作是類型為[] int的切片。sum可以接收任意數量的int型參數:
fmt.Println(sum()) // "0" fmt.Println(sum(3)) // "3" fmt.Println(sum(1, 2, 3, 4)) // "10"
在上面的代碼中,調用者隱式的創建一個數組,並將原始參數復制到數組中,再把數組的一個切片作為參數傳給被調函數。如果原始參數已經是切片類型,我們該如何傳遞給sum?只需在最后一個參數后加上省略符。下面的代碼功能與上個例子中最后一條語句相同。
values := []int{1, 2, 3, 4} fmt.Println(sum(values...)) // "10"
雖然在可變參數函數內部,...int 型參數的行為看起來很像切片類型,但實際上,可變參數函數和以切片作為參數的函數是不同的。
func f(...int) {} func g([]int) {} fmt.Printf("%T\n", f) // "func(...int)" fmt.Printf("%T\n", g) // "func([]int)"
可變參數函數經常被用於格式化字符串。下面的errorf函數構造了一個以行號開頭的,經過格式化的錯誤信息。函數名的后綴f是一種通用的命名規范,代表該可變參數函數可以接收Printf風格的格式化字符串。
func errorf(linenum int, format string, args ...interface{}) { fmt.Fprintf(os.Stderr, "Line %d: ", linenum) fmt.Fprintf(os.Stderr, format, args...) fmt.Fprintln(os.Stderr) } linenum, name := 12, "count" errorf(linenum, "undefined: %s", name) // "Line 12: undefined: count"
interfac{}表示函數的最后一個參數可以接收任意類型