最近与同事讨论时,提到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语言 可变参数的更多相关文章

  1. 转:C语言 可变参数

    C语言 可变参数 堆栈一般是怎么压栈处理的 /* * stack space: * *        参数3   |    up *        参数2   | *        参数1   v   ...

  2. C语言 可变参数

    一.基础部分 1.1 什么是可变长参数 可变长参数:顾名思义,就是函数的参数长度(数量)是可变的.比如 C 语言的 printf 系列的(格式化输入输出等)函数,都是参数可变的.下面是 printf ...

  3. C语言可变参数函数实现原理

    一.可变参数函数实现原理 C函数调用的栈结构: 可变参数函数的实现与函数调用的栈结构密切相关,正常情况下C的函数参数入栈规则为__stdcall, 它是从右到左的,即函数中的最右边的参数最先入栈. 本 ...

  4. 深入C语言可变参数(va_arg,va_list,va_start,va_end,_INTSIZEOF)

    一.什么是可变参数 在C语言编程中有时会遇到一些参数个数可变的函数,例如printf(),scanf()函数,其函数原型为: int printf(const char* format,…),int ...

  5. C语言可变参数在宏定义中的应用

    在C语言的标准库中,printf.scanf.sscanf.sprintf.sscanf这些标准库的输入输出函数,参数都是可变的.在调试程序时,我们可能希望定义一个参数可变的输出函数来记录日志,那么用 ...

  6. C语言可变参数函数的编写

    1. 引言 C语言我们接触的第一个库函数是 printf(“hello,world!”);其参数个数为1个. 然后,我们会接触到诸如: printf(“a=%d,b=%s,c=%c”,a,b,c);此 ...

  7. C语言可变参数va_list

    一.什么是可变参数 在C语言编程中有时会遇到一些参数个数可变的函数,例如printf(),scanf()函数,其函数原型为: int printf(const char* format,-) int ...

  8. C语言可变参数

    前段时候在实现利用redis进行的一个数据库比对的功能,稍微去分析了一下redis里面的源代码,然后发现其中的发送命令接口声明如下: void *redisCommand(redisConnect * ...

  9. c语言可变参数函数

    c语言支持可变参数函数.这里的可变指,函数的参数个数可变. 其原理是,一般情况下,函数参数传递时,其压栈顺序是从右向左,栈在虚拟内存中的增长方向是从上往下.所以,对于一个函数调用 func(int a ...

随机推荐

  1. DOTNET CORE源码分析之IOC容器结果获取内容补充

    补充一下ServiceProvider的内容 可能上一篇文章DOTNET CORE源码分析之IServiceProvider.ServiceProvider.IServiceProviderEngin ...

  2. Javascript十六种常用设计模式

    单例模式 何为单例模式,就是无论执行多少次函数,都只会生成一个对象哈哈,看一个简单的demo function Instance(name) { this.name = name; } Instanc ...

  3. 【简说Python WEB】flask-mail电子邮件异步Asynchronous

    系统环境:Ubuntu 18.04.1 LTS Python使用的是虚拟环境:virutalenv Python的版本:Python 3.6.9 flask-mail电子邮件异步Asynchronou ...

  4. Apex_2. LiveBos两个时间求相差天数、历时

    (1)获取两个时间相差天数(没有上午下午区分) var d1=ABS_DATESTRING(FStartTime,'yyyy/MM/dd'); var d2=ABS_DATESTRING(FEndTi ...

  5. Comparing Data-Independent Acquisition and Parallel Reaction Monitoring in Their Abilities To Differentiate High-Density Lipoprotein Subclasses 比较DIA和PRM区分高密度脂蛋白亚类的能力 (解读人:陈凌云)

    文献名:Comparing Data-Independent Acquisition and Parallel Reaction Monitoring in Their Abilities To Di ...

  6. Selenium系列(一) - 8种元素定位方式的详细解读

    安装Selenium和下载Driver 安装selenium pip3 install  selenium -i http://pypi.douban.com/simple --trusted-hos ...

  7. 学习笔记----C语言的面向对象

    2020-03-26    21:27:17 面向对象的编程语言都有一个类的概念,像Java.python等.类是对特定数据的特定操作的集合体.它包含两个范畴:数据和操作.C语言是没有类的概念的,但是 ...

  8. Leetcode_474. 一和零(二维01背包)

    每个字符串看成一个物品,两个属性是0和1的个数,转换为01背包. code class Solution { public: int w[605][2]; int dp[105][105]; int ...

  9. [源码分析] 从FlatMap用法到Flink的内部实现

    [源码分析] 从FlatMap用法到Flink的内部实现 0x00 摘要 本文将从FlatMap概念和如何使用开始入手,深入到Flink是如何实现FlatMap.希望能让大家对这个概念有更深入的理解. ...

  10. 从 ASP.NET Core 3.1 迁移到 5.0

    3月中旬,微软官方已经发布了dotnet 5的第一个预览版:5.0.0-preview.1. dotnet core经过前几个版本的发展和沉淀,到3.1已经基本趋于稳定. 所以从.net core 3 ...