所谓变长参数指的是函数参数的数量不确定,可以按照需要传递任意数量的参数到指定函数,比如前面演示过的 fmt.Printf 函数的参数显然就是变长参数。

Go 语言中的变长参数

合适地使用变长参数,可以让代码更简洁,尤其是输入输出类函数,比如日志函数。接下来,作为对比,我们来介绍下 Go 语言中的变长参数的用法,和 PHP 类似,只是把 … 作用到类型上,这样就可以约束变长参数的类型:

  1. package main
  2. import "fmt"
  3. func myFunc(numbers ...int) {
  4. for _, number := range numbers {
  5. fmt.Println(number)
  6. }
  7. }
  8. func main() {
  9. myFunc(1, 2, 3, 4, 5)
  10. }

或者还可以传递一个数组切片,传递切片时需要在末尾加上 … 作为标识,表示对应的参数类型是变长参数:

  1. package main
  2. import "fmt"
  3. func myFunc(numbers ...int) {
  4. for _, number := range numbers {
  5. fmt.Println(number)
  6. }
  7. }
  8. func main() {
  9. myFunc(1, 2, 3, 4, 5)
  10. slice1 := []int{7, 8, 9, 10}
  11. myFunc(slice1...)
  12. }

从底层实现原理上看,类型 …type 本质上是一个数组切片,也就是 []type,这也是为什么上面的参数 numbers 可以用 for 循环来获取每个传入的参数值。

任意类型的变长参数

PHP 是弱类型语言,声明变长参数时不需要指定参数类型,Go 语言则不同,但是用过 fmt.Printf 函数的同学可能知道,我们可以向其中传递任意类型的参数值,可见 Go 语言也可以支持传递任意类型的值作为变成参数,那这又是如何实现的呢?答案是可以指定变长参数类型为 interface{}(空接口类型可以用于表示任意类型)

  1. package main
  2. import (
  3. "fmt"
  4. "reflect"
  5. )
  6. func myPrintf(args ...interface{}) {
  7. for _, arg := range args {
  8. switch reflect.TypeOf(arg).Kind() {
  9. case reflect.Int:
  10. fmt.Println(arg, "is an int value.")
  11. case reflect.String:
  12. fmt.Printf("\"%s\" is a string value.\n", arg)
  13. case reflect.Array:
  14. fmt.Println(arg, "is an array type.")
  15. case reflect.Bool:
  16. fmt.Println(arg, "is an bool type.")
  17. case reflect.Slice:
  18. fmt.Println(arg, "is an Slice type.")
  19. default:
  20. fmt.Println(arg, "is an unknown type.")
  21. }
  22. }
  23. }
  24. func main() {
  25. myPrintf(1, "1", [1]int{1}, true,[]string{"111"})
  26. }