支持可变长参数列表的函数可以支持任意个传入参数,比如fmt.Println函数就是一个支持可变长参数列表的函数。
需要注意的是,可变长参数应该是函数定义的最右边的参数,即最后一个参数
package main import "fmt" // 这个函数可以传入任意数量的整型参数 func sum(nums ...int) { fmt.Println(nums) total := 0 for i, num := range nums { fmt.Println(i) total += num } fmt.Println(total) } func main() { // 支持可变长参数的函数调用方法和普通函数一样 // 也支持只有一个参数的情况 sum(1) sum(1, 2) sum(1, 2, 3) // 如果你需要传入的参数在一个切片中,像下面一样 // "func(slice...)"把切片打散传入 nums := []int{1, 2, 3, 4} sum(nums...) }
输出结果:
[1] 0 1 [1 2] 0 1 3 [1 2 3] 0 1 2 6 [1 2 3 4] 0 1 2 3 10
=============== 坑 =====================
package main import( "fmt" ) func TestArgs(first int,arg ...interface{}){ fmt.Println(first,arg) } func main(){ nums:=[]int64{1,2,3,4} TestArgs(1,nums...) }
想要实现的代码逻辑很明了
1. TestArgs 接受一个 int 参数,可变长的参数,并且类型为 interface{}
2. nums 做为 slice,使用 ... 语法打散后传入 TestArgs
看上去逻辑没问题,但编译报错
[root@YY yang]# go build tt.go # command-line-arguments ./tt.go:13:11: cannot use nums (type []int64) as type []interface {} in argument to TestArgs
居然报类型不匹配,写 Go 也一年了,这块的认知太不到位,一直认为会将 nums 打散,再以 interface{} 这个通用类型组成 interface{} slice 传到 TestArgs
那么,我们看看到底 nums 传进去后是什么
package main import ( "fmt" "reflect" ) func TestArgs(first int, arg ...interface{}) { fmt.Println(first, reflect.TypeOf(arg)) } func main() { nums := []interface{}{1, 2, 3, 4} TestArgs(1, nums...) }
执行结果
[root@YY yang]# ./tt 1 []interface {}
那么确认是把可变参数当做 slice 传给函数,这点和 python 很像。那我们再看看 slice 是不是同一个
package main import ( "fmt" "reflect" ) func TestArgs(first int, arg ...interface{}) { fmt.Println(first, reflect.TypeOf(arg)) fmt.Printf("TestArgs addr of slice %p\n", arg) fmt.Println(arg) } func main() { nums := []interface{}{1, 2, 3, 4} fmt.Printf("TestArgs addr of slice %p\n", nums) TestArgs(1, nums...) TestArgs(2, "abc", "def", "ghlfk") }
执行后输出如下
[root@YY yang]# ./tt TestArgs addr of slice 0xc42004a040 1 []interface {} TestArgs addr of slice 0xc42004a040 [1 2 3 4] 2 []interface {} TestArgs addr of slice 0xc420058150 [abc def ghlfk]
nums和arg地址相同!原来,如果传入的可变参数本身就是由 slice 以 ... 形式传入的,那么就直接使用这个 slice,不会新建 slice。那么我理解的 Go 的可变参数执行方式:
对于 func(first int, arg ...T) 1. 当不传可变参数时,对应的 arg 就是 nil 2. 传入单个可变参数时,实际上执行 [] T{arg1,arg2,arg3} 3. 传入...语法的 slice时,直接使用这个 slice 由此我们就很好理解开篇的小例子为什么执行不了,[]int64 和 []interface{} 是两个类型的 slice 。
转自:https://www.jianshu.com/p/94710d8ab691