Go 语言可变参数怎么用能最大化它的效用?本文对可变参数进行了详细介绍。
在实际开发中,总有一些函数的参数个数是在编码过程中无法确定的,比如我们最常用的 fmt.Printf 和 fmt.Println:
fmt.Printf(
"一共有%v 行%v 列、n"
, rows, cols)

fmt.Println(
"共计大小:"
, size)

当你需要实现类似的接口时,就需要我们的可变参数出场了。

golang 的可变参数

可变参数就是一个占位符,你可以将 1 个或者多个参数赋值给这个占位符,这样不管实际参数的数量是多少,都能交给可变参数来处理,我们看一下可变参数的声明:
funcPrintf(format string, a ...interface{})(n int, err error)
funcPrintln(a ...interface{})(n int, err error)
可变参数使用 name ...Type 的形式声明在函数的参数列表中,而且需要是参数列表的最后一个参数,这点与其他语言类似;
可变参数在函数中将转换为对应的 []Type 类型,所以我们可以像使用 slice 时一样来获取传给函数的参数们;
有一点值得注意,golang 的可变参数不需要强制绑定参数的出现。
举个例子,我想在 c 语言中实现一个求和任意个整数的函数 sum:
int
 sum(
int
 num, ...) {

// todo
}

我们只有先指定至少一个固定的形参(num)才能使用。.. 可变参数,在 golang 中是不需要这样做的:
funcsum(nums ...int)int
 {

//todo
}

这也是 golang 语法简洁的其中一个体现。

传递参数给。.. 可变参数

传递参数给带有可变参数的函数有两种形式,第一种与通常的参数传递没有什么区别,拿上一节的 sum 举个例子:
sum(
1
2
3
)

sum(
1
2
3
4
5
6
7
8
9
10
)

除了参数的个数是动态变化的之外和普通的函数调用是一致的。
第二种形式是使用。.. 运算符以变量。.. 的形式进行参数传递,这里的变量必须是与可变参数类型相同的 slice,而不能是其他类型(没错,数组也不可以),看个例子:
numbers := []
int
{
1
2
3
4
5
6
7
8
9
10
}

sum(numbers...) 
// 和 sum(1, 2, 3, 4, 5, 6, 7, 8, 9. 10) 等价
这种形式最常用的地方是在内置函数 append 里:
result := []
int
{
1
3
}

data := []
int
{
5
7
9
}

result = 
append
(result, data...) 
// result == []int{1, 3, 5, 7, 9}
是不是和 python 的解包操作很像,没错,大部分情况下你可以把。.. 运算符当做是 golang 的 unpack 操作,不过有几点不同还是要注意的:
第一,只能对 slice 类型使用。.. 运算符:
arr := [...]
int
{
1
2
3
4
5
}

sum(arr...) 
// 编译无法通过
你会见到这样的报错信息:cannot use arr (type [5]int) as type []int in argument to sum
这是因为可变参数实际是个 slice,... 运算符是个语法糖,它把前面的 slice 直接复制给可变参数,而不是先解包成独立的 n 个参数再传递,这也是为什么我只说。.. 运算符看起来像 unpack 的原因。
第二个需要注意的地方是不能把独立传参和 ... 运算符混用,再看个例子:
slice := []
int
{
2
3
4
5
}

sum(
1
, slice...) 
// 无法通过编译
这次你会见到一个比较长的报错:
too many arguments in call to sum

    have (number, []
int
...)

    want (...
int
)

这是和前面所说的原因是一样的,... 运算符将不定参数直接替换成了 slice,这样就导致前一个独立给出的参数不再算入可变参数的范围内,使得函数的参数列表从 (...int) 变成了 (int, ...int),最终使得函数类型不匹配编译失败。
正确的做法也很简单,不要混合使用。.. 运算符给可变参数传参即可。
读了这篇文章,再加上一些简单的联系,我相信你们一定也能掌握 golang 可变参数的使用。

参考:

https://golang.org/ref/spec#Passing_arguments_to_..._parameters
https://golang.org/doc/effective_go.html#append
转自:
cnblogs.com/apocelipes/p/9861315.html
文章转载:Go开发大全
(版权归原作者所有,侵删)

点击下方“阅读原文”查看更多
继续阅读
阅读原文