[奔跑的 Go] 教程十一、深入学习 Go 语言的「可变参数函数」
可变函数接受无限个参数,所有这些参数都存储在切片类型的参数中。
什么是可变函数?
正如我们在 functions
课程中看到的 , 函数是一段专门用于完成特定工作的代码。 函数接受一个或多个参数,并返回一个或多个值。 可变函数 也是函数,但它们也可以采用 无限 或 变量 的 参数. 听起来很蠢,但我们在slices
课中看到过,当append
函数接受变量参数时。
func f(elem ...Type)
可变参数函数的典型语法如上所示。...
操作符被称为 打包操作符指明将所有类型为Type
的参数存储在名为 elem
的参数中。使用这种语法,go创建了类型为[]type
的elem
的变量,它是一个切片。因此,传递给这个函数的所有参数都存储在这个名为elem
的切片中。
让我们来看一下append
函数的例子。
append([]Type, args, arg2, argsN)
append
函数要求第一个参数是类型Type
的slice
,之后可以有可变数量的参数。如果我们有一个切片s2
我们想要添加到一个切片s1
中,要如何实现呢?
从append
函数语法来看,我们不能传递另一个切片作为参数,它必须是一个或多个type
类型的参数。因此,我们将使用解包操作符 …
将切片分解到一系列参数中( 以满足*append*
函数的参数要求)。
append(s1, s2...)
...
表示pack(打包)
和unpack(解包)
操作符,如果省略号位于一个切片的尾部位置,则会分解这个切片。
这里 s1
和 s2
是两个相同的切片类型。通常函数的入参及其数量都是已知的。但是 **append**
函数是如何知晓其入参的数量的呢?
如果你看下 append
函数的签名,
func append(slice []Type, elems ...Type) []Type
你会发现 elems ...Type
指的是将所有入参变量打包进首个参数之后的 elems
切片中。
值得注意的是只允许函数的最后一个参数是可变的。
所以 append
首个参数是切片类型是因为它要求如此,但是其后的变量则会被打包进一个 elems
变量中。希望你已经清楚明了,现在我们来创建自自定义的 可变
函数。
☛ 如何创建可变函数?
如前所述,可变函数只是一个接受可变数量参数的函数。为了使函数接受可变数量的参数,我们需要使用pack(打包)
操作符... Type
。
解包操作符以
...
结束如slice ...
,而打包操作以...
开头,如... Type
。
下面让我们来编写getMultiples
函数,其第一个参数是int(整形)
类型,它作为乘法因子,后面的变量参数(*名为** 可变 参数 *)实则是一个名为args
的切片,这个切片的类型为int(整形)
。
在这个函数中,我们使用make
函数创建了一个名为multiples
的空切片,其长度等于args
切片的长度。然后使用for range
,我们将factor
与args
切片中的每个元素相乘并将它们填充到multiples
的切片中。之后,我们返回这个进行相乘之后的切片multiples
。
func getMultiples(factor int, args ...int) []int {
multiples := make([]int, len(args))
for index, val := range args {
multiples[index] = val * factor
}
return multiples
}
这很简单,我们可以像这样在 main
函数中实现这个函数:
func main() {
s := []int{10, 20, 30}
mult1 := getMultiples(2, s...)
mult2 := getMultiples(3, 1, 2, 3, 4)
fmt.Println(mult1)
fmt.Println(mult2)
}
https://play.golang.org/p/BgU6H9orhrn
在上面的例子中,当你将切片
s
作为参数直接传递到getMultiples
函数时,会发生什么?显然,编译器会报错cannot use s (type []int) as type int in argument to getMultiples
因为切片的类型是[]int
而getMultiples
函数期望的参数类型是int
。
☛ slice
是如何传递给可变参数函数的?
由于切片是对数组的引用,那么当您使用解包操作符将切片传递给可变参数函数时会发生什么? go 会创建新的切片 args
还是保持切片 s
不变呢?因为我们没有任何的工具可以来判断 args == s
,所以我们需要对 args
切片本身来进行修改,以检查原始切片是否发生了改变。
https://play.golang.org/p/fbNgVGu6JZO
在上面的程序中,我们稍微修改了 getMultiples
可变参数函数,我们没有创建新的切片,而是将乘积赋值给 args
本身,用乘积元素替换传入的元素。
在上面的结果中,我们可以看到,切片 s
的值发生了改变。这意味着, go 在使用 unpack
操作符将 slice
作为参数传递给可变参数函数时,会使用其关联的底层数组构建一个新的切片。所以,请小心使用。
本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。
推荐文章: