前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Go 语言基础入门教程 —— 函数篇:变长参数

Go 语言基础入门教程 —— 函数篇:变长参数

作者头像
学院君
发布2019-08-08 10:01:11
5520
发布2019-08-08 10:01:11
举报
文章被收录于专栏:学院君的专栏学院君的专栏

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

PHP 中的变长参数简介

PHP 函数也支持变长参数,在 PHP 5.5 及更早版本中,可以在定义函数时设置参数为空,然后在函数体中通过 func_num_args()func_get_arg() 以及 func_get_args() 之类的函数获取参数数量及参数值:

代码语言:javascript
复制
function sum()
{
    $sum = 0;
    $numbers = func_get_args();
    foreach ($numbers as $number) {
        $sum += $number;
    }
    printf("The num of the arguments are %d\n", func_num_args());
    printf("The sum of the numbers are %d\n", $sum);
}

sum(1, 2, 3, 4, 5);

从 PHP 5.6 开始,变长参数的定义和其他语言的风格保持一致:

代码语言:javascript
复制
function sum(...$numbers)
{
    $sum = 0;
    foreach ($numbers as $number) {
        $sum += $number;
    }
    printf("The num of the arguments are %d\n", func_num_args());
    printf("The sum of these numbers are %d\n", $sum);
}

sum(1, 2, 3, 4, 5);

Go 语言中的变长参数

基本定义和传值

合适地使用变长参数,可以让代码更简洁,尤其是输入输出类函数,比如日志函数。

接下来,作为对比,我们来介绍下 Go 语言中的变长参数的用法,和 PHP 类似,只是把 ... 作用到类型上,这样就可以约束变长参数的类型:

代码语言:javascript
复制
func myfunc(numbers ...int) {
    for _, number := range numbers {
        fmt.Println(number)
    }
}

这段代码的意思是,函数 myfunc() 接受不定数量的参数,这些参数的类型全部是 int,所以它可以通过如下方式调用:

代码语言:javascript
复制
myfunc(1, 2, 3, 4, 5)

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

代码语言:javascript
复制
slice := []int{1, 2, 3, 4, 5}
myfunc(slice...)
myfunc(slice[1:3]...)

形如 ...type 格式的类型只能作为函数的参数类型存在,并且必须是函数的最后一个参数。

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

假如没有 ...type 这样的语法糖,开发者将不得不这么写:

代码语言:javascript
复制
func myfunc2(numbers []int) { 
    for _, number := range numbers { 
        fmt.Println(number) 
    } 
}

从函数的实现角度来看,这没有任何影响,但从调用方来说,情形则完全不同:

代码语言:javascript
复制
myfunc2([]int{1, 2, 3, 4, 5})

你会发现,我们不得不加上 []int{} 来构造一个数组切片实例。但是有了 ...type 这个语法糖,我们就不用自己来处理了。

任意类型的变长参数

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

答案是可以指定变长参数类型为 interface{}(空接口类型可以用于表示任意类型,后面我们在 Go 语言面向对象编程中会具体介绍),下面是 Go 语言标准库中 fmt.Printf() 的函数原型:

代码语言:javascript
复制
func Printf(format string, args ...interface{}) { 
    // ...
}

下面我们来自定义一个支持任意类型的变长参数函数,用于判断传入参数的类型:

代码语言:javascript
复制
func myPrintf(args ...interface{}) {
    for _, arg := range args {
        switch reflect.TypeOf(arg).Kind() {
        case reflect.Int:
            fmt.Println(arg, "is an int value.")
        case reflect.String:
            fmt.Printf("\"%s\" is a string value.\n", arg)
        case reflect.Array:
            fmt.Println(arg, "is an array type.")
        default:
            fmt.Println(arg, "is an unknown type.")
        }
    }
}

func main() {
    myPrintf(1, "1", [1]int{1}, true)
}

该程序的输出结果为:

代码语言:javascript
复制
1 is an int value.
"1" is a string value.
[1] is an array type.
false is an unknown type.
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-07-05,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 极客书房 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • PHP 中的变长参数简介
  • Go 语言中的变长参数
    • 基本定义和传值
      • 任意类型的变长参数
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档