[11 Go语言基础-可变参数函数]

可变参数函数

什么是可变参数函数

可变参数函数是一种参数个数可变的函数。

语法

如果函数最后一个参数被记作 ...T ,这时函数可以接受任意个 T 类型参数作为最后一个参数。

请注意只有函数的最后一个参数才允许是可变的。

通过一些例子理解可变参数函数如何工作

你是否曾经想过 append 函数是如何将任意个参数值加入到切片中的。这样 append 函数可以接受不同数量的参数。

func append(slice []Type, elems ...Type) []Type

上面是 append 函数的定义。在定义中 elems 是可变参数。这样 append 函数可以接受可变化的参数。

让我们创建一个我们自己的可变参数函数。我们将写一段简单的程序,在输入的整数列表里查找某个整数是否存在。

package main

import (
"fmt"
) func find(num int, nums ...int) {
fmt.Printf("type of nums is %T\n", nums)
found := false
for i, v := range nums {
if v == num {
fmt.Println(num, "found at index", i, "in", nums)
found = true
}
}
if !found {
fmt.Println(num, "not found in ", nums)
}
fmt.Printf("\n")
}
func main() {
find(89, 89, 90, 95)
find(45, 56, 67, 45, 90, 109)
find(78, 38, 56, 98)
find(87)
}

在上面程序中 func find(num int, nums ...int) 中的 nums 可接受任意数量的参数。在 find 函数中,参数 nums 相当于一个整型切片。

可变参数函数的工作原理是把可变参数转换为一个新的切片。以上面程序中的第 22 行为例,find 函数中的可变参数是 89,90,95 。 find 函数接受一个 int 类型的可变参数。因此这三个参数被编译器转换为一个 int 类型切片 int []int{89, 90, 95} 然后被传入 find函数。

在第 10 行, for 循环遍历 nums 切片,如果 num 在切片中,则打印 num 的位置。如果 num 不在切片中,则打印提示未找到该数字。

上面代码的输出值如下,

type of nums is []int
89 found at index 0 in [89 90 95] type of nums is []int
45 found at index 2 in [56 67 45 90 109] type of nums is []int
78 not found in [38 56 98] type of nums is []int
87 not found in []

在上面程序的第 25 行,find 函数仅有一个参数。我们没有给可变参数 nums ...int 传入任何参数。这也是合法的,在这种情况下 nums 是一个长度和容量为 0 的 nil 切片。

给可变参数函数传入切片

下面例子中,我们给可变参数函数传入一个切片,看看会发生什么。

package main

import (
"fmt"
) func find(num int, nums ...int) {
fmt.Printf("type of nums is %T\n", nums)
found := false
for i, v := range nums {
if v == num {
fmt.Println(num, "found at index", i, "in", nums)
found = true
}
}
if !found {
fmt.Println(num, "not found in ", nums)
}
fmt.Printf("\n")
}
func main() {
nums := []int{89, 90, 95}
find(89, nums)
}

在第 23 行中,我们将一个切片传给一个可变参数函数。

这种情况下无法通过编译,编译器报出错误 main.go:23: cannot use nums (type []int) as type int in argument to find

为什么无法工作呢?原因很直接,find 函数的说明如下,

func find(num int, nums ...int)

由可变参数函数的定义可知,nums ...int 意味它可以接受 int 类型的可变参数。

在上面程序的第 23 行,nums 作为可变参数传入 find 函数。前面我们知道,这些可变参数参数会被转换为 int 类型切片然后在传入 find 函数中。但是在这里 nums 已经是一个 int 类型切片,编译器试图在 nums 基础上再创建一个切片,像下面这样

find(89, []int{nums})

这里之所以会失败是因为 nums 是一个 []int类型 而不是 int类型。

那么有没有办法给可变参数函数传入切片参数呢?答案是肯定的。

有一个可以直接将切片传入可变参数函数的语法糖,你可以在在切片后加上 ... 后缀。如果这样做,切片将直接传入函数,不再创建新的切片

在上面的程序中,如果你将第 23 行的 find(89, nums) 替换为 find(89, nums...) ,程序将成功编译并有如下输出

type of nums is []int
89 found at index 0 in [89 90 95]

下面是完整的程序供您参考。

package main

import (
"fmt"
) func find(num int, nums ...int) {
fmt.Printf("type of nums is %T\n", nums)
found := false
for i, v := range nums {
if v == num {
fmt.Println(num, "found at index", i, "in", nums)
found = true
}
}
if !found {
fmt.Println(num, "not found in ", nums)
}
fmt.Printf("\n")
}
func main() {
nums := []int{89, 90, 95}
find(89, nums...)
}

不直观的错误

当你修改可变参数函数中的切片时,请确保你知道你正在做什么。

下面让我们来看一个简单的例子。

package main

import (
"fmt"
) func change(s ...string) {
s[0] = "Go"
} func main() {
welcome := []string{"hello", "world"}
change(welcome...)
fmt.Println(welcome)
}

你认为这段代码将输出什么呢?如果你认为它输出 [Go world] 。恭喜你!你已经理解了可变参数函数和切片。如果你猜错了,那也不要紧,让我来解释下为什么会有这样的输出。

在第 13 行,我们使用了语法糖 ... 并且将切片作为可变参数传入 change 函数。

正如前面我们所讨论的,如果使用了 ...welcome 切片本身会作为参数直接传入,不需要再创建一个新的切片。这样参数 welcome 将作为参数传入 change 函数

change 函数中,切片的第一个元素被替换成 Go,这样程序产生了下面的输出值

[Go world]

这里还有一个例子来理解可变参数函数。

package main

import (
"fmt"
) func change(s ...string) {
s[0] = "Go"
s = append(s, "playground")
fmt.Println(s)
} func main() {
welcome := []string{"hello", "world"}
change(welcome...)
fmt.Println(welcome)
}


可变长参数(小练习)

package main

import "fmt"

// 可变长参数

func main() {
//test2("11111","2")
var a []string=[]string{"lqz","egon"}
test2(a...) // 把切片传入 } func test2(a ...string) { // a是切片
fmt.Println(a)
fmt.Println(a[1])
fmt.Printf("%T",a)
a=append(a,"lqz")
fmt.Println(a)
}

[11 Go语言基础-可变参数函数]的更多相关文章

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

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

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

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

  3. c语言可变参数函数

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

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

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

  5. C语言中可变参数的函数(三个点,“...”)

    C语言中可变参数的函数(三个点,“...”) 本文主要介绍va_start和va_end的使用及原理. 在以前的一篇帖子Format MessageBox 详解中曾使用到va_start和va_end ...

  6. C语言中的可变参数函数

    C语言编程中有时会遇到一些参数个数可变的函数,例如printf()函数,其函数原型为: int printf( const char* format, ...); 它除了有一个参数format固定以外 ...

  7. C语言学习020:可变参数函数

    顾名思义,可变参数函数就是参数数量可变的函数,即函数的参数数量是不确定的,比如方法getnumbertotal()我们即可以传递一个参数,也可以传递5个.6个参数 #include <stdio ...

  8. C语言可变参数函数详解示例

    先看代码 printf(“hello,world!”);其参数个数为1个. printf(“a=%d,b=%s,c=%c”,a,b,c);其参数个数为4个. 如何编写可变参数函数呢?我们首先来看看pr ...

  9. php匿名函数和可变参数函数

    php匿名函数和可变参数函数 简介 直接上代码了: <?php $test1 = function($value) { echo $value; }; $test1('HelloWorld'); ...

随机推荐

  1. Java:java获取Linux下的路径

    指定Linux的路径 //Linux系统路径 StringBuilder sb = new StringBuilder(File.separator); String Url = sb.append( ...

  2. robotframework使用过程中的一些总结

    p.p1 { margin: 0; font: 20px "Helvetica Neue"; color: rgba(53, 53, 53, 1) } p.p2 { margin: ...

  3. 将Acunetix与CircleCI集成

    如果要在DevSecOps中包含Acunetix ,则需要将其与CI / CD系统集成.Acunetix具有针对最受欢迎的CI / CD系统Jenkins的现成集成.但是,您可以使用Acunetix ...

  4. 【Azure 应用服务】Azure Function App使用SendGrid发送邮件遇见异常消息The operation was canceled,分析源码逐步最终源端

    问题描述 在使用Azure Function App的SendGrid Binging功能,调用SendGrid服务器发送邮件功能时,有时候遇见间歇性,偶发性异常.在重新触发SendGrid部分的Fu ...

  5. Flask(9)- 蓝图的基本使用

    前言 在前面的例子中,所有的页面处理逻辑都是放在同一个文件中,随着业务代码的增加,将所有代码都放在单个程序文件中是非常不合适的 不仅会让阅读代码变得困难,而且会给后期维护带来麻烦 Flask 中使用蓝 ...

  6. Spring Cloud中的注解

    一.Eureka @EnableEurekaServer: @EnableDiscoverClient:标注服务是一个Eureka的客户端 @LoadBalanced:自动构造LoadBalancer ...

  7. Java和C#语法对比(转)

        Java C# 访问修饰符 public 修饰类.接口.变量.方法. 对所有类可见. 修饰类.接口.变量.方法. 对所有类可见.   internal 无. 修饰类.接口.变量.方法. 类,接 ...

  8. Java | 参数传值机制

    值传递 java中,方法中所有的参数的都是"值传递",就是传递的是原来值的副本,不是原来的参数,因此,改变不会影响到原来的参数. 基本数据类型参数的传值 传递的都是副本,改变以后不 ...

  9. QT从入门到入土(三)——信号和槽机制

    摘要 信号槽是 Qt 框架引以为豪的机制之一.所谓信号槽,实际就是观察者模式.当某个事件发生之后,比如,按钮检测到自己被点击了一下,它就会发出一个信号 (signal).这种发出是没有目的的,类似广播 ...

  10. C语言:易错题

    1. int x=y=z=0;//实际只声明了变量x,而变量y,z并没有声明.可以修改为:int x=0,y=0,z=0; 或int x,y,z; x=y=z=0; 2.int z=(x+y)++;/ ...