了解golang的可变参数(... parameters),这一篇就够了
在实际开发中,总有一些函数的参数个数是在编码过程中无法确定的,比如我们最常用的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),这一篇就够了的更多相关文章
- golang 中可变参数的个数
package main import "fmt" func Greeting(prefix string, who ... string) { fmt.Println(prefi ...
- 坑爹的 Java 可变参数,把我整得够惨。。
最近在写一个功能点,用了 Java 中的可变参数,真是把我搞得够惨.. 什么是可变参数? 就是方法参数用 Object... args 三个点形式,一个参数可以接收多个参数. 实际的代码就不帖了,来看 ...
- 【GoLang】golang 中可变参数的 定义、传递 示例
支持可变长参数列表的函数可以支持任意个传入参数,比如fmt.Println函数就是一个支持可变长参数列表的函数. package main import "fmt" // 这个函数 ...
- SpringMVC参数绑定,这篇就够了!
SpringMVC参数绑定,简单来说就是将客户端请求的key/value数据绑定到controller方法的形参上,然后就可以在controller中使用该参数了 下面通过5个常用的注解演示下如何进行 ...
- params可变参数、SqlCommand.Parameters.add()方法
namespace params可变参数{ class Program { static void Main(string[] args) { int[] num = {66,99,55,44, }; ...
- Python星号*与**用法分析 What does ** (double star/asterisk) and * (star/asterisk) do for parameters? 必选参数 默认参数 可变参数 关键字参数
python中*号**的区别 - CSDN博客 https://blog.csdn.net/qq_26815677/article/details/78091452 定义可变参数和定义 list 或 ...
- golang中函数的可变参数
package main import "fmt" // 一个函数中最多只可有一个可变参数, 如果参数列表中还有其它类型的参数,则可变参数写在最后 // 注意:参数不定,参数的个数 ...
- 【转载】va_list 可变参数 简介 va_copy vprintf
[说明]本文转载自 smart 的文章 http://blog.sina.com.cn/s/blog_590be5290100qhxr.html 及百度百科 va_list是一个宏,由va_star ...
- 可变参数列表-Java SE5新特性(转)
Java1.5增加了新特性:可变参数:适用于参数个数不确定,类型确定的情况,java把可变参数当做数组处理.注意:可变参数必须位于最后一项.当可变参数个数多于一个时,必将有一个不是最后一项,所以只支持 ...
随机推荐
- <笔记>原生PHP访问TP模板变量
在模板中,原生PHP可以直接访问模板变量,不过如果模板变量是数组,要访问数组中元素时不能使用"."符号,只能通过数组['元素名']的方式
- Metasploit漏洞的利用
- 友链 & 日记
友链 & 日记 关于 \(Owen\) 温州中学初三 \(OIer\),目前 \(OI\) 水平一般,文化课成绩浮在中游.喜欢二次元,喜欢听音乐,标准宅一枚.虽然入宅时间很短 欢迎大家跟 \( ...
- C/C++ 多线程机制
一.C/C++多线程操作说明 C/C++多线程基本操作如下: 1. 线程的建立结束 2. 线程的互斥和同步 3. 使用信号量控制线程 4. 线程的基本属性配置 在C/C++代码编写时,使用多线程机制, ...
- Java 使用 int 数据计算百分比
int diliverNum=3;//举例子的变量 int queryMailNum=9;//举例子的变量 // 创建一个数值格式化对象 NumberFormat numberFormat = Num ...
- 查看windows到期时间
查看windows到期时间 Slmgr.vbs -xpr
- 把ajax包装成promise的形式(2)
概述 为了体验promise的原理,我打算自己把ajax包装成promise的形式.主要希望实现下列功能: // 1.使用success和error进行链式调用,并且可以在后面加上无限个 promis ...
- CentOS随笔——关机命令
关机重启命令 在linux领域内大多用在服务器上,很少遇到关机的操作.毕竟服务器上跑一个服务是永无止境的,除非特殊情况面,不得已才会关机. 正确的关机流程为:sync>shutdown>r ...
- alert换行
alert( "视频会议系统开启流程 " + String.fromCharCode(13) + "1. 软件下载之后双击安装即可." + String.fr ...
- RocketMQ
http://rocketmq.apache.org/docs/quick-start/ 解压后添加启动脚本 nohup sh bin/mqnamesrv >> logs/namesrv. ...