在实际开发中,总有一些函数的参数个数是在编码过程中无法确定的,比如我们最常用的fmt.Printf和fmt.Println:

fmt.Printf("一共有%v行%v列\n", rows, cols)
fmt.Println("共计大小:", size)

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

golang的可变参数

可变参数就是一个占位符,你可以将1个或者多个参数赋值给这个占位符,这样不管实际参数的数量是多少,都能交给可变参数来处理,我们看一下可变参数的声明:

func Printf(format string, a ...interface{}) (n int, err error)
func Println(a ...interface{}) (n int, err error)

可变参数使用name ...Type的形式声明在函数的参数列表中,而且需要是参数列表的最后一个参数,这点与其他语言类似;

可变参数在函数中将转换为对应的[]Type类型,所以我们可以像使用slice时一样来获取传给函数的参数们;

有一点值得注意,golang的可变参数不需要强制绑定参数的出现。

举个例子,我想在c语言中实现一个求和任意个整数的函数sum:

int sum(int num, ...) {
// todo
}

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

func sum(nums ...int) int {
//todo
}

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

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

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

sum(, , )
sum(, , , , , , , , , )

除了参数的个数是动态变化的之外和普通的函数调用是一致的。

第二种形式是使用...运算符以变量...的形式进行参数传递,这里的变量必须是与可变参数类型相同的slice,而不能是其他类型(没错,数组也不可以),看个例子:

numbers := []int{, , , , , , , , , }
sum(numbers...) // 和sum(1, 2, 3, 4, 5, 6, 7, 8, 9. 10)等价

这种形式最常用的地方是在内置函数append里:

result := []int{, }
data := []int{, , }
result = append(result, data...) // result == []int{1, 3, 5, 7, 9}

是不是和python的解包操作很像,没错,大部分情况下你可以把...运算符当做是golang的unpack操作,不过有几点不同还是要注意的:

第一,只能对slice类型使用...运算符:

arr := [...]int{, , , , }
sum(arr...) // 编译无法通过

你会见到这样的报错信息:cannot use arr (type [5]int) as type []int in argument to sum

这是因为可变参数实际是个slice,...运算符是个语法糖,它把前面的slice直接复制给可变参数,而不是先解包成独立的n个参数再传递,这也是为什么我只说...运算符看起来像unpack的原因。

第二个需要注意的地方是不能把独立传参和...运算符混用,再看个例子:

slice := []int{, , , }
sum(, 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

了解golang的可变参数(... parameters),这一篇就够了的更多相关文章

  1. golang 中可变参数的个数

    package main import "fmt" func Greeting(prefix string, who ... string) { fmt.Println(prefi ...

  2. 坑爹的 Java 可变参数,把我整得够惨。。

    最近在写一个功能点,用了 Java 中的可变参数,真是把我搞得够惨.. 什么是可变参数? 就是方法参数用 Object... args 三个点形式,一个参数可以接收多个参数. 实际的代码就不帖了,来看 ...

  3. 【GoLang】golang 中可变参数的 定义、传递 示例

    支持可变长参数列表的函数可以支持任意个传入参数,比如fmt.Println函数就是一个支持可变长参数列表的函数. package main import "fmt" // 这个函数 ...

  4. SpringMVC参数绑定,这篇就够了!

    SpringMVC参数绑定,简单来说就是将客户端请求的key/value数据绑定到controller方法的形参上,然后就可以在controller中使用该参数了 下面通过5个常用的注解演示下如何进行 ...

  5. params可变参数、SqlCommand.Parameters.add()方法

    namespace params可变参数{ class Program { static void Main(string[] args) { int[] num = {66,99,55,44, }; ...

  6. Python星号*与**用法分析 What does ** (double star/asterisk) and * (star/asterisk) do for parameters? 必选参数 默认参数 可变参数 关键字参数

    python中*号**的区别 - CSDN博客 https://blog.csdn.net/qq_26815677/article/details/78091452 定义可变参数和定义 list 或 ...

  7. golang中函数的可变参数

    package main import "fmt" // 一个函数中最多只可有一个可变参数, 如果参数列表中还有其它类型的参数,则可变参数写在最后 // 注意:参数不定,参数的个数 ...

  8. 【转载】va_list 可变参数 简介 va_copy vprintf

    [说明]本文转载自 smart 的文章 http://blog.sina.com.cn/s/blog_590be5290100qhxr.html  及百度百科 va_list是一个宏,由va_star ...

  9. 可变参数列表-Java SE5新特性(转)

    Java1.5增加了新特性:可变参数:适用于参数个数不确定,类型确定的情况,java把可变参数当做数组处理.注意:可变参数必须位于最后一项.当可变参数个数多于一个时,必将有一个不是最后一项,所以只支持 ...

随机推荐

  1. SJCP认证题前五十题填坑

    在做Java的SJCP认证试题时自己整理了一些Java基础细节知识点,以下是知识点陈列 1.标签机制:标签起作用的唯一的地方刚好在迭代语句之前(不然编译错误) continue label1 直接转到 ...

  2. enumerate的用法

    names = ["tony","huluwa","tom","jerry","lala"]for ...

  3. <笔记>字体文件的路径问题

    如果做过虚拟域名,不可以通过127.0.0.1来访问字体文件 改成通过虚拟域名访问,就没问题: 不过更建议使用相对路径

  4. Windows平台最方便最易用的法语输入法

    原文:http://wenwen.sogou.com/z/q1700007921.htm 对于XP,在“控制面板”中选择“输入法区域设置”,单击“更改”,出现一个“设置”框:选择“添加”,然后选择“法 ...

  5. vue computed计算属性和watch监听属性解疑答惑

    computed计算属性     计算属性类似于方法,用于输出data中定义的属性数据的结果,data数据变化时,计算属性的结果会同步变化,需要注意的是计算属性不可与data定义的属性同名. 相比于方 ...

  6. MyBatis的好处及常见问题

    好处 MyBatis持久层框架,它对jdbc的操作数据库的过程进行封装,使开发者只需要关注 SQL 本身,而不需要花费精力去处理例如注册驱动.创建connection.创建statement.手动设置 ...

  7. 微信小程序中如何使用WebSocket实现长连接(含完整源码)

    本文由腾讯云技术团队原创,感谢作者的分享. 1.前言   微信小程序提供了一套在微信上运行小程序的解决方案,有比较完整的框架.组件以及 API,在这个平台上面的想象空间很大.腾讯云研究了一番之后,发现 ...

  8. Android开发之如何避免ANR(Keeping Your App Responsive)

    一:什么是ANR 如果应用程序不能响应用户的输入了,那么就可以说应用ANR了. 如果需要运行一个耗时较长的操作的时候,不要把这个任务放在UI线程上运行,而是单独创建一个线程运行那些操作. 以下情况会出 ...

  9. .net core 发布linux报错“The configured user limit (128) on the number of inotify instances has been reached”

    https://stackoverflow.com/questions/45875981/error-while-reading-json-file-in-dotnet-core-the-config ...

  10. Java 虚拟机的内存溢出

    在Java虚拟机规范的描述中,除了程序计数器外,虚拟机内存的其他几个运行时区域都有发生 OutOfMemoryError 异常的可能. 在Eclipse中进行JVM参数设置 可以直接通过上方菜单栏的 ...