最近与同事讨论时,提到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. Python程序设计试验报告一: 熟悉IDLE和在线编程平台

    安徽工程大学 Python程序设计 实验报告                                                                  班级   物流192   ...

  2. git版本控制系统小白教程(上)

    前言:本文主要介绍git版本控制系统的一些基础使用,适合小白入门,因为内容较多,会分为两部分进行分享. Git介绍 ​ Git是目前世界上最先进的分布式版本控制系统.并且它是一个开源的分布式版本控制系 ...

  3. 2. python提示:TypeError: unhashable type: 'list'

    原因是,python字典的key不支持list类型和dict类型,需要转换 错误时 将list类型强制转换成string,用"".join(list). 修改后:

  4. IE浏览器下载文件中文文件名乱码问题解决

    处理过程 根据IE的F12中的log提示,是因为http头信息中的编码替换了html文件中的编码.我最初的思路是设置Tomcat默认编码,但是我发现我已经在Server.xml中设置过,想到这里我想到 ...

  5. POJ1780 欧拉路+手写栈解决爆战问题

    题目链接:http://poj.org/problem?id=1780 本题中给出一个位数n,要求给出一个10^n+n-1位数的数,要求每个n位的数都要在里面出现,一个n位的数一共有10^n种,我们容 ...

  6. hdu2087kmp模板练习

    题目网址:http://icpc.njust.edu.cn/Problem/Hdu/2087/ 代码: #include<bits/stdc++.h> using namespace st ...

  7. Java attack - Java 特性

    Java 语言平台版本 l  J2SE (Java 2 Platform Standard Edition) 标准版 是为开发普通桌面和商务应用程序提供的解决方案,该技术体系是其他两者的基础,可以完成 ...

  8. UVA129 Krypton Factor 困难的串 dfs回溯【DFS】

     Krypton Factor Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others ...

  9. Python第六章-函数05-迭代器&生成器

    python作为一个既面向对象,又支持函数式编程的语言,函数的使用方面有很多特点. 比如:闭包,装饰器,迭代器等 函数的高级应用 容器:生活中常见的容器有哪些?袋子,盆子,水杯,书包,铅笔盒... 容 ...

  10. 纯干货 C# 通过 RFC_READ_TABLE 读取 SAP TABLE

    SAP系统又称企业管理解决方案,是全球企业管理软件与解决方案的技术领袖,同时也是市场领导者.通过其应用软件.服务与支持,SAP持续不断向全球各行业企业提供全面的企业级管理软件解决方案. 在实际开发过程 ...