本文共 2677 字,大约阅读时间需要 8 分钟。
在上篇文章里,讲解了关于函数的概念和用法,函数接收的参数数目都是确定的。而可变参数函数的参数数目是不确定的,这一节,就来讲讲可变参数函数 。
可变参数函数,接收可变数量的参数的函数。如果一个函数的最后一个参数的表示形如:...Type
,则该参数(形参)可以接受不同数目的参数(实参)。
func f(elems ...Type)
需要注意的一点,只允许最后一个参数是可变参数。
Go 中的一些内置函数都是可变参数函数,例如:append()
函数: func append(slice []Type, elems ...Type) []Type
在上面的函数声明中,elems
就是可变参数,可以接收任意数目的实参。
s := []int{ 1,2,3}s = append(s,4,5,6,7,8)
你是不是也很想知道,为什么可变参数函数能够接收任意数目的参数呢?
刚开始学的时候,我也很疑惑。现在一步步给你揭开它的面纱。func change(str1 string, s ...string) { fmt.Println(str1) fmt.Printf("%T\n",s) // %T 输出变量类型 fmt.Println(s)}func main() { blog := "seekload.net" change(blog,"Hello","World","Go")}
:
seekload.net[]string[Hello World Go]
从输出结果看出,change()
函数中,参数s
是[]string
类型的切片。
change()
函数时可变参数是Hello
、World
、Go
,这三个参数被编译器转化成切片[]string{"Hello","World","Go"}
,然后被传入change()
函数。 另外,调用change()
函数时候,可以不传可变参数,在 Go 语言里也是合法的,这种情况下,s
是一个长度和容量都是 0 的 nil 切片。 func change(str1 string, s ...string) { fmt.Println(str1) fmt.Printf("%T\n",s) fmt.Println(s)}func main() { slice := []string{ "Hello","World","Go"} blog := "seekload.net" change(blog,slice)}
上述代码中,将切片slice
传给可变参数函数change()
,结果编译出错:cannot use slice (type []string) as type string in argument to change
。
s ...string
意味它可以接受 string 类型的可变参数。代码第 10 行,slice
作为可变参数传入change()
函数。前面我们知道,可变参数会被转换为 string 类型切片然后再传入change()
函数中。但slice
是一个 string 类型的切片,编译器试图通过下面这种方式在slice
基础上再创建一个切片: change("seekload.net", []string{ s})
之所以会失败,因为slice
是[]string
类型,而不是string
类型。
...
后缀。这样,切片将直接传入函数,不会再创建新的切片。 修改上面的代码: change(blog,slice...)
:
seekload.net[]string[Hello World Go]
前面提到一点,通过 Go 提供的语法糖将可变参数函数传入切片,不会创建新的切片。如果在函数中改变切片的值会发生什么呢?
func change(s ...string) { s[0] = "seekload.net" fmt.Printf("%T\n",s) fmt.Println(s)}func main() { slice := []string{ "Hello","World","Go"} change(slice...) fmt.Println(slice)}
:
[]string[seekload.net World Go][seekload.net World Go]
从结果可以看出,main()
函数的切片已经改变了。
...
并且将切片作为可变参数传入change()
函数。如上面讨论的,如果使用了...
,切片本身会作为参数直接传入,不会再创建一个新的切片。所以在change()
函数中,第一个元素被替换成 ,会影响到main()
函数的切片。 另外,我们也可以通过将数组转化成切片传递给可变参数函数。
func change(s ...string) { s[0] = "seekload.net" fmt.Printf("%T\n",s) fmt.Println(s)}func main() { arr := [3]string{ "Hello","World","Go"} change(arr[:]...) fmt.Println(arr)}
输出结果跟上面的例子是一样的。
给大家列几种比较常见的写法:
func change(s ...string) { fmt.Printf("%T\n",s) fmt.Println(s)}func main() { slice1 := []string{ "Hello","World","Go"} slice2 := []string{ "Aa","Bb"} // 1、 change(append(slice1,"Again")...) // 2、 change(append(slice1,slice2...)...)}
输出:
[]string[Hello World Go Again][]string[Hello World Go Aa Bb]
希望这篇文章对你有用!
参考:
1、 2、Go 语言文档:、转载地址:http://ybfnb.baihongyu.com/