Go语言 可变参数
最近与同事讨论时,提到Go语言的可变参数,之前没有总结过相关知识点,今天我们介绍一下Go语言的可变参数。
可变参数(Variable Parameters):参数数量可变的函数称之为可变参数函数,主要是在使用语法糖(syntactic sugar)。最经典的例子就是fmt.Printf()和类似的函数,fmt.Printf首先接收一个参数,后面可接收若干个参数。
在开始Go语言实例之前,我们先看一下在C语言里面是如何实现可变参数的,如示例:
#include <stdio.h>
#include <stdarg.h>
int sum(int count, ...)
{
int sum=0;
int val=0;
// 定义一个可变参数列表,可以看成是一种特殊的指针类型,list指向的对象是栈上的数据。
va_list list;
// 初始化list,list指向第一个被压栈的参数,即函数的最后一个参数,而count则是栈上最后一个参数,系统由此确定栈上参数内存的范围。
va_start(list, count);
while(count--)
{
// 通过va_arg依次获取参数值,两个参数,一个是指向栈上参数的指针list,
// 这个指针每取出一个数据移动一次,总是指向栈上第一个未取出的参数,
// int指需要取出的参数的类型,CPU根据这个类型所占的地址空间来进行寻址。
val = va_arg(list,int);
// printf("%d at %X\n", val, &val);
sum += val;
}
//释放list,释放后list置为空。
va_end(list);
return sum;
}
int main()
{
printf("Sum of 1,2,3,4,5 = %d\n", sum(5, 1, 2, 3, 4, 5));
printf("Sum of 10,20,30 = %d\n", sum(3, 10,20,30));
}
运行结果:

我们可以看到,在C语言里面,需要指定参数个数和若干个参数,下面我们介绍一下Go语言中的实现。
实例一:
func1使用的是Go语言的语法糖,按照内部机制来说,...type本质是一个切片,也就是[]type,params被看作是类型为[] int的切片传入func1中,func1可接收任意个int值,返回sum结果。
虽然在可变参数函数内部,...int型参数的行为看起来类似slice,实际上,可变参数函数和切片作为参数的函数是不相同的。
// 可变参数
func func1(params ...int) {
sum := 0
for _, param := range params {
sum += param
}
fmt.Println("params : ", params, "\tsum : ", sum)
}
调用一:
func TestFunc1(t *testing.T) {
var params = []int{1, 2, 3}
func1(params...)
func1(2, 5)
func1(2, 5, 8)
}
结果一:
=== RUN TestFunc1
params : [1 2 3] sum : 6
params : [2 5] sum : 7
params : [2 5 8] sum : 15
--- PASS: TestFunc1 (0.00s)
实例二:
func2虽然同样实现了不定参数的功能,但是使用起来比较繁琐,需要[]type{}来构造切片实例。我们可以看到传递的数据是slice,但是在参数传递的时候,我们需要手工初始化slice再传入函数。
// 切片
func func2(params []int) {
sum := 0
for _, param := range params {
sum += param
}
fmt.Println("params : ", params, "\tsum : ", sum)
}
调用二:
func TestFunc2(t *testing.T) {
func2([]int{3})
func2([]int{3, 6})
func2([]int{3, 6, 9})
}
结果二:
=== RUN TestFunc2
params : [3] sum : 3
params : [3 6] sum : 9
params : [3 6 9] sum : 18
--- PASS: TestFunc2 (0.00s)
综上两例,我们可以看出语法糖实现更简洁方便。
实例三:
我们再看一下可变类型的可变参数,见func3:
// 可变类型的可变参数
func func3(params ...interface{}) {
for _, param := range params {
switch reflect.TypeOf(param).Kind().String() {
case "int":
fmt.Printf("param:%d is an int value!\n", param)
case "int32":
fmt.Printf("param:%v is an int32 value!\n", param)
case "int64":
fmt.Printf("param:%v is an int64 value!\n", param)
case "float32":
fmt.Printf("param:%v is an float32 value!\n", param)
case "float64":
fmt.Printf("param:%v is an float64 value!\n", param)
case "string":
fmt.Printf("param:%s is an string value!\n", param)
case "func":
fmt.Printf("param:%v is an func value!\n", param)
case "map":
fmt.Printf("param:%v is an map value!\n", param)
default:
fmt.Printf("param:%v is an unknown type.\n", param)
}
}
}
调用三:
func TestFunc3(t *testing.T) {
var p1 int = 100 //传递int值
func3(p1)
var p2 int32 = 200 //传递int32
func3(p2)
var p3 int64 = 300 //传递int64
func3(p3)
var p4 = "test string" //传递string
func3(p4)
var p5 float32 = 1.11 //传递float32
func3(p5)
var p6 float64 = 2.22 //传递float64
func3(p6)
var p7 = func(a, b int) int { return a + b } //传递func
func3(p7)
var p8 = map[string]string{} ////传递map
func3(p8)
}
结果三:
=== RUN TestFunc3
param:100 is an int value!
param:200 is an int32 value!
param:300 is an int64 value!
param:test string is an string value!
param:1.11 is an float32 value!
param:2.22 is an float64 value!
param:0x506b50 is an func value!
param:map[] is an map value!
--- PASS: TestFunc3 (0.00s)
PASS
总结:
可变参数,主要是Go语言的语法糖之"...type"的使用。
参数个数灵活。
Go语言 可变参数的更多相关文章
- 转:C语言 可变参数
C语言 可变参数 堆栈一般是怎么压栈处理的 /* * stack space: * * 参数3 | up * 参数2 | * 参数1 v ...
- C语言 可变参数
一.基础部分 1.1 什么是可变长参数 可变长参数:顾名思义,就是函数的参数长度(数量)是可变的.比如 C 语言的 printf 系列的(格式化输入输出等)函数,都是参数可变的.下面是 printf ...
- C语言可变参数函数实现原理
一.可变参数函数实现原理 C函数调用的栈结构: 可变参数函数的实现与函数调用的栈结构密切相关,正常情况下C的函数参数入栈规则为__stdcall, 它是从右到左的,即函数中的最右边的参数最先入栈. 本 ...
- 深入C语言可变参数(va_arg,va_list,va_start,va_end,_INTSIZEOF)
一.什么是可变参数 在C语言编程中有时会遇到一些参数个数可变的函数,例如printf(),scanf()函数,其函数原型为: int printf(const char* format,…),int ...
- C语言可变参数在宏定义中的应用
在C语言的标准库中,printf.scanf.sscanf.sprintf.sscanf这些标准库的输入输出函数,参数都是可变的.在调试程序时,我们可能希望定义一个参数可变的输出函数来记录日志,那么用 ...
- C语言可变参数函数的编写
1. 引言 C语言我们接触的第一个库函数是 printf(“hello,world!”);其参数个数为1个. 然后,我们会接触到诸如: printf(“a=%d,b=%s,c=%c”,a,b,c);此 ...
- C语言可变参数va_list
一.什么是可变参数 在C语言编程中有时会遇到一些参数个数可变的函数,例如printf(),scanf()函数,其函数原型为: int printf(const char* format,-) int ...
- C语言可变参数
前段时候在实现利用redis进行的一个数据库比对的功能,稍微去分析了一下redis里面的源代码,然后发现其中的发送命令接口声明如下: void *redisCommand(redisConnect * ...
- c语言可变参数函数
c语言支持可变参数函数.这里的可变指,函数的参数个数可变. 其原理是,一般情况下,函数参数传递时,其压栈顺序是从右向左,栈在虚拟内存中的增长方向是从上往下.所以,对于一个函数调用 func(int a ...
随机推荐
- requests模块使用一
1.安装与简介 Urllib和requests模块是python中发起http请求最常见的模块,但是requests模块使用更加方便简单. pip install requests 2.GET请求 2 ...
- Shell中的参数传递
原文链接 我们先来定义一个方法 function methodName() { paramName1=$1 paramName2=$2 paramName3=$3 # 依此类推,参数是从1开始标号,而 ...
- Journal of Proteome Research | Clinically Applicable Deep Learning Algorithm Using Quantitative Proteomic Data (分享人:翁海玉)
题目:Clinically Applicable Deep Learning Algorithm Using Quantitative Proteomic Data 期刊:Journal of Pro ...
- 【攻防世界】open-source
难度系数: 3.0 题目来源: Pediy CTF 2018 题目描述:菜鸡发现Flag似乎并不一定是明文比较的 先用:PE查壳,发现没有
- win7系统下的Nodejs开发环境配置
此处不推荐使用msi安装包直接安装nodejs,我们应该知道它里面做了哪些事情,这样以后出问题的时候,可以更快速地定位问题点.另一方面,直接安装的情况,以后更新了版本的话会很麻烦,因为如果我们想体验新 ...
- JSP(二)----指令,注释,内置对象
## JSP 1.指令 * 作用:用于配置JSP页面,导入资源文件 * 格式: <%@ 指令名称 属性名1=属性值1 属性名2=属性值2 %> <%@ page con ...
- VScode+phpStudy搭建php代码调试环境
一.安装Visual Studio Code 官网:https://code.visualstudio.com/ 下载安装包后,按照默认安装即可 安装中文语言环境 点击左侧工具栏的 extension ...
- 使用条件随机场模型解决文本分类问题(附Python代码)
对深度学习感兴趣,热爱Tensorflow的小伙伴,欢迎关注我们的网站!http://www.tensorflownews.com.我们的公众号:磐创AI. 一. 介绍 世界上每天都在生成数量惊人的文 ...
- Python第七章-面向对象高级
面向对象高级 一. 特性 特性是指的property. property这个词的翻译一直都有问题, 很多人把它翻译为属性, 其实是不恰当和不准确的. 在这里翻译成特性是为了和属性区别开来. 属性是指的 ...
- coding++:java-HashMap的负载因子为什么默认是0.75?
本篇文章基于JDK1.8,特在此说明 1):负载因子的作用 负载因子是和扩容机制有关的,意思是如果当前容器的容量,达到了我们设定的最大值,就要开始执行扩容操作.举个例子来解释,避免小白听不懂: 比如说 ...