前天同事提起了一个例子,关于 Golang 中可变参数的使用,平时使用时没有注意这个细节,先上代码吧。

测试代码

想要实现的代码逻辑很明了

1. TestArgs 接受一个 int 参数,一个不定长的参数,并且类型为 interface{}

2. nums 做为 slice,使用 ... 语法糖打散后传入 TestArgs

看上去逻辑没问题,执行报错

# command-line-arguments

./test.go:13: cannot use nums (type []int64) as type []interface {} in argument to TestArgs

居然报类型不匹配,写 Go 也一年了,这块的认知太不到位,一直认为会将 nums 打散,再以 interface{} 这个通用类型组成 interface{} slice 传到 TestArgs。

那么,我们看看到底 nums 传进去后是什么:

slice

再执行后输出 []interface {},那么确认是把可变参数当做 slice 传给函数,这点和 python 很像。那我们再看看 slice 是不是同一个

取地址

执行后输出如下

main addr of slice 0xc82000c0c0

TestArgs addr of slice 0xc82000c0c0

地址相同,原来如果传入的可变参数本身就是由 slice 以 ... 形式传入的,那么就直接使用这个 slice,不会新建 slice。那么我理解的 Go 的可变参数执行方式:

对于 func(first int, arg ...T)

1. 当不传可变参数时,对应的 arg 就是 nil

2. 传入单个可变参数时,实际上执行 [] T{arg1,arg2,arg3}

3. 传入...语法糖的 slice时,直接使用这个 slice

由此我们就很好理解开篇的小例子为什么执行不了,[]int64 和 []interface{} 是两个类型的 slice 。