可变参数

golang语言规范

Passing arguments to ... parameters

https://golang.org/ref/spec#Passing_arguments_to_..._parameters

如果 f 是变数(variadic),其最终参数p的类型为…T,那么在 f 中,p的类型等同于类型 []T。如果调用f时,p没有实际参数,那么传递给p的值就是nil。否则,传递的值是一个类型为 []T 的新的底层数组的分片,其连续的元素是实际的参数,这些参数都必须是可以分配给T的,因此分片的长度和容量是与p绑定的参数数字,对于每个调用点来说可能会有所不同。

给定函数和调用:

func Greeting(prefix string, who ...string)
Greeting("nobody")
Greeting("hello:", "Joe", "Anna", "Eileen")

Greeting在第一次调用时的值为nil,第二次调用时的值为 []string{“Joe”, “Anna”, “Eileen”} 。

如果最后的参数可以分配给一个分片类型 []T,那么如果参数后面有 …T 参数,它将作为 …T 参数的值不变地传递。在这种情况下,不会创建新的分片。

给定分片s并调用

s := []string{"James", "Jasmine"}
Greeting("goodbye:", s...)

在Greeting,它的值将与s的底层数组相同。

摘要:Go 语言“可变参数函数”终极指南

https://studygolang.com/articles/11965

可变参数函数即其参数数量是可变的 —— 0 个或多个。声明可变参数函数的方式是在其参数类型前带上省略符(三个点)前缀。

可变参数的使用场景:

  • 避免创建仅作传入参数用的临时切片
  • 当参数数量未知
  • 传达你希望增加可读性的意图

可变参数函数会在其内部创建一个”新的切片”。事实上,可变参数是一个简化了切片类型参数传入的语法糖。

当不传入参数的时候,可变参数会成为一个空值切片( nil ):

所有的非空切片都有内建的数组,而 nil 切片则没有。

然而,当你向 nil 切片添加元素时,它会自动内建一个包含该元素的数组。这个切片也就再也不是一个 nil 切片了。

可以通过向一个已有的切片添加可变参数运算符 ”…“ 后缀的方式将其传入可变参数函数。

names := []string{"carl", "sagan"}

toFullname(names...)

这就好比通常的传参方式:

toFullname("carl", "sagan")

不过,这里还是有一点差异:函数会在内部直接使用这个传入的切片,并不会创建一个的新的。

可以像下面这样将数组转化成切片后传入可变参数函数:

names := [2]string{"carl", "sagan"}

toFullname(names[:]...)

传入的切片和函数内部使用的切片共享同一个底层数组,因此在函数内部改变这个数组的值同样会影响到传入的切片:

参考资料