gopl-zh.github.com/ch5/ch5-07.md
chai2010 c28e6f2899 ch5-7: fix code
Fixes #69
2016-01-10 15:38:48 +08:00

2.8 KiB
Raw Blame History

5.7. 可變參數

參數數量可變的函數稱爲爲可變參數函數。典型的例子就是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{}表示函數的最後一個參數可以接收任意類型我們會在第7章詳細介紹。

練習5.15 編寫類似sum的可變參數函數max和min。考慮不傳參時max和min該如何處理再編寫至少接收1個參數的版本。

**練習5.16**編寫多參數版本的strings.Join。

**練習5.17**編寫多參數版本的ElementsByTagName函數接收一個HTML結點樹以及任意數量的標籤名返迴與這些標籤名匹配的所有元素。下面給出了2個例子

func ElementsByTagName(doc *html.Node, name...string) []*html.Node
images := ElementsByTagName(doc, "img")
headings := ElementsByTagName(doc, "h1", "h2", "h3", "h4")