歡迎來(lái)到 Golang 系列教程 第 12 部分
什么是可變參數(shù)函數(shù)
可變參數(shù)函數(shù)是一種參數(shù)個(gè)數(shù)可變的函數(shù)。
語(yǔ)法
如果函數(shù)最后一個(gè)參數(shù)被記作 ...T
,這時(shí)函數(shù)可以接受任意個(gè) T
類(lèi)型參數(shù)作為最后一個(gè)參數(shù)寡喝。
請(qǐng)注意只有函數(shù)的最后一個(gè)參數(shù)才允許是可變的糙俗。
通過(guò)一些例子理解可變參數(shù)函數(shù)如何工作
你是否曾經(jīng)想過(guò) append 函數(shù)是如何將任意個(gè)參數(shù)值加入到切片中的勒奇。這樣 append 函數(shù)可以接受不同數(shù)量的參數(shù)。
func append(slice []Type, elems ...Type) []Type
上面是 append 函數(shù)的定義巧骚。在定義中 elems 是可變參數(shù)赊颠。這樣 append 函數(shù)可以接受可變化的參數(shù)。
讓我們創(chuàng)建一個(gè)我們自己的可變參數(shù)函數(shù)劈彪。我們將寫(xiě)一段簡(jiǎn)單的程序竣蹦,在輸入的整數(shù)列表里查找某個(gè)整數(shù)是否存在。
package main
import (
"fmt"
)
func find(num int, nums ...int) {
fmt.Printf("type of nums is %T\n", nums)
found := false
for i, v := range nums {
if v == num {
fmt.Println(num, "found at index", i, "in", nums)
found = true
}
}
if !found {
fmt.Println(num, "not found in ", nums)
}
fmt.Printf("\n")
}
func main() {
find(89, 89, 90, 95)
find(45, 56, 67, 45, 90, 109)
find(78, 38, 56, 98)
find(87)
}
在線運(yùn)行代碼
在上面程序中 func find(num int, nums ...int)
中的 nums
可接受任意數(shù)量的參數(shù)沧奴。在 find 函數(shù)中痘括,參數(shù) nums
相當(dāng)于一個(gè)整型切片。
可變參數(shù)函數(shù)的工作原理是把可變參數(shù)轉(zhuǎn)換為一個(gè)新的切片。以上面程序中的第 22 行為例纲菌,find
函數(shù)中的可變參數(shù)是 89挠日,90,95 翰舌。 find 函數(shù)接受一個(gè) int
類(lèi)型的可變參數(shù)嚣潜。因此這三個(gè)參數(shù)被編譯器轉(zhuǎn)換為一個(gè) int 類(lèi)型切片 int []int{89, 90, 95}
然后被傳入 find
函數(shù)。
在第 10 行椅贱, for
循環(huán)遍歷 nums
切片,如果 num
在切片中懂算,則打印 num
的位置。如果 num
不在切片中,則打印提示未找到該數(shù)字庇麦。
上面代碼的輸出值如下,
type of nums is []int
89 found at index 0 in [89 90 95]
type of nums is []int
45 found at index 2 in [56 67 45 90 109]
type of nums is []int
78 not found in [38 56 98]
type of nums is []int
87 not found in []
在上面程序的第 25 行计技,find 函數(shù)僅有一個(gè)參數(shù)。我們沒(méi)有給可變參數(shù) nums ...int
傳入任何參數(shù)女器。這也是合法的酸役,在這種情況下 nums
是一個(gè)長(zhǎng)度和容量為 0 的 nil
切片。
給可變參數(shù)函數(shù)傳入切片
下面例子中驾胆,我們給可變參數(shù)函數(shù)傳入一個(gè)切片涣澡,看看會(huì)發(fā)生什么。
package main
import (
"fmt"
)
func find(num int, nums ...int) {
fmt.Printf("type of nums is %T\n", nums)
found := false
for i, v := range nums {
if v == num {
fmt.Println(num, "found at index", i, "in", nums)
found = true
}
}
if !found {
fmt.Println(num, "not found in ", nums)
}
fmt.Printf("\n")
}
func main() {
nums := []int{89, 90, 95}
find(89, nums)
}
在線運(yùn)行代碼
在第23行中丧诺,我們將一個(gè)切片傳給一個(gè)可變參數(shù)函數(shù)入桂。
這種情況下無(wú)法通過(guò)編譯,編譯器報(bào)出錯(cuò)誤 main.go:23: cannot use nums (type []int) as type int in argument to find
驳阎。
為什么無(wú)法工作呢抗愁?原因很直接,find
函數(shù)的說(shuō)明如下呵晚,
func find(num int, nums ...int)
由可變參數(shù)函數(shù)的定義可知蜘腌,nums ...int
意味它可以接受 int
類(lèi)型的可變參數(shù)。
在上面程序的第 23 行饵隙,nums
作為可變參數(shù)傳入 find
函數(shù)撮珠。前面我們知道,這些可變參數(shù)參數(shù)會(huì)被轉(zhuǎn)換為 int
類(lèi)型切片然后在傳入 find
函數(shù)中金矛。但是在這里 nums
已經(jīng)是一個(gè) int 類(lèi)型切片芯急,編譯器試圖在 nums
基礎(chǔ)上再創(chuàng)建一個(gè)切片,像下面這樣
find(89, []int{nums})
這里之所以會(huì)失敗是因?yàn)?nums
是一個(gè) []int
類(lèi)型 而不是 int
類(lèi)型驶俊。
那么有沒(méi)有辦法給可變參數(shù)函數(shù)傳入切片參數(shù)呢娶耍?答案是肯定的。
有一個(gè)可以直接將切片傳入可變參數(shù)函數(shù)的語(yǔ)法糖饼酿,你可以在在切片后加上 ...
后綴榕酒。
如果這樣做胚膊,切片將直接傳入函數(shù),不再創(chuàng)建新的切片
在上面的程序中想鹰,如果你將第 23 行的 find(89, nums)
替換為 find(89, nums...)
澜掩,程序?qū)⒊晒幾g并有如下輸出
type of nums is []int
89 found at index 0 in [89 90 95]
下面是完整的程序供您參考。
package main
import (
"fmt"
)
func find(num int, nums ...int) {
fmt.Printf("type of nums is %T\n", nums)
found := false
for i, v := range nums {
if v == num {
fmt.Println(num, "found at index", i, "in", nums)
found = true
}
}
if !found {
fmt.Println(num, "not found in ", nums)
}
fmt.Printf("\n")
}
func main() {
nums := []int{89, 90, 95}
find(89, nums...)
}
不直觀的錯(cuò)誤
當(dāng)你修改可變參數(shù)函數(shù)中的切片時(shí)杖挣,請(qǐng)確保你知道你正在做什么肩榕。
下面讓我們來(lái)看一個(gè)簡(jiǎn)單的例子。
package main
import (
"fmt"
)
func change(s ...string) {
s[0] = "Go"
}
func main() {
welcome := []string{"hello", "world"}
change(welcome...)
fmt.Println(welcome)
}
在線運(yùn)行代碼
你認(rèn)為這段代碼將輸出什么呢惩妇?如果你認(rèn)為它輸出 [Go world]
株汉。恭喜你!你已經(jīng)理解了可變參數(shù)函數(shù)和切片歌殃。如果你猜錯(cuò)了乔妈,那也不要緊,讓我來(lái)解釋下為什么會(huì)有這樣的輸出氓皱。
在第 13 行路召,我們使用了語(yǔ)法糖 ...
并且將切片作為可變參數(shù)傳入 change
函數(shù)。
正如前面我們所討論的波材,如果使用了 ...
股淡,welcome
切片本身會(huì)作為參數(shù)直接傳入,不需要再創(chuàng)建一個(gè)新的切片廷区。這樣參數(shù) welcome
將作為參數(shù)傳入 change
函數(shù)
在 change
函數(shù)中唯灵,切片的第一個(gè)元素被替換成 Go
,這樣程序產(chǎn)生了下面的輸出值
[Go world]
這里還有一個(gè)例子來(lái)理解可變參數(shù)函數(shù)隙轻。
package main
import (
"fmt"
)
func change(s ...string) {
s[0] = "Go"
s = append(s, "playground")
fmt.Println(s)
}
func main() {
welcome := []string{"hello", "world"}
change(welcome...)
fmt.Println(welcome)
}
在線運(yùn)行代碼
我將把它作為一個(gè)練習(xí)留個(gè)你埠帕,請(qǐng)你指出上面的程序是如何運(yùn)行的 :) 。
以上就是關(guān)于可變參數(shù)函數(shù)的介紹玖绿。感謝閱讀敛瓷。歡迎您留下有價(jià)值的反饋和意見(jiàn)。祝您生活愉快斑匪。
下一教程 - Maps
via: https://golangbot.com/variadic-functions/
作者:Nick Coghlan
譯者:fengchunsgit
校對(duì):Noluye
本文由 GCTT 原創(chuàng)編譯呐籽,Go 中文網(wǎng) 榮譽(yù)推出