博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
可变函数 -- 就要学习 Go 语言
阅读量:2288 次
发布时间:2019-05-09

本文共 2677 字,大约阅读时间需要 8 分钟。

在上篇文章里,讲解了关于函数的概念和用法,函数接收的参数数目都是确定的。而可变参数函数的参数数目是不确定的,这一节,就来讲讲可变参数函数

可变参数函数

可变参数函数,接收可变数量的参数的函数。如果一个函数的最后一个参数的表示形如:...Type,则该参数(形参)可以接受不同数目的参数(实参)。

func f(elems ...Type)

需要注意的一点,只允许最后一个参数是可变参数。

Go 中的一些内置函数都是可变参数函数,例如:append()函数:

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

在上面的函数声明中,elems就是可变参数,可以接收任意数目的实参。

s := []int{
1,2,3}s = append(s,4,5,6,7,8)

如何工作

你是不是也很想知道,为什么可变参数函数能够接收任意数目的参数呢?

刚开始学的时候,我也很疑惑。现在一步步给你揭开它的面纱。

func change(str1 string, s ...string) {
fmt.Println(str1) fmt.Printf("%T\n",s) // %T 输出变量类型 fmt.Println(s)}func main() {
blog := "seekload.net" change(blog,"Hello","World","Go")}

seekload.net[]string[Hello World Go]

从输出结果看出,change()函数中,参数s[]string类型的切片。

可变参数函数的工作原理就是把可变参数转化成切片。 调用change()函数时可变参数是HelloWorldGo,这三个参数被编译器转化成切片[]string{"Hello","World","Go"} ,然后被传入change()函数。
另外,调用change()函数时候,可以不传可变参数,在 Go 语言里也是合法的,这种情况下,s是一个长度和容量都是 0 的 nil 切片。

其他用法

将切片传递给可变参数函数
func change(str1 string, s ...string) {
fmt.Println(str1) fmt.Printf("%T\n",s) fmt.Println(s)}func main() {
slice := []string{
"Hello","World","Go"} blog := "seekload.net" change(blog,slice)}

上述代码中,将切片slice传给可变参数函数change(),结果编译出错:cannot use slice (type []string) as type string in argument to change

原因很简单,由可变参数函数的定义可知,s ...string 意味它可以接受 string 类型的可变参数。代码第 10 行,slice作为可变参数传入change()函数。前面我们知道,可变参数会被转换为 string 类型切片然后再传入change()函数中。但slice是一个 string 类型的切片,编译器试图通过下面这种方式在slice基础上再创建一个切片:

change("seekload.net", []string{
s})

之所以会失败,因为slice[]string类型,而不是string类型。

庆幸的是,Go 提供了将切片传入可变参数函数的语法糖:直接在切片后加上...后缀。这样,切片将直接传入函数,不会再创建新的切片。
修改上面的代码:

change(blog,slice...)

seekload.net[]string[Hello World Go]

前面提到一点,通过 Go 提供的语法糖将可变参数函数传入切片,不会创建新的切片。如果在函数中改变切片的值会发生什么呢?

func change(s ...string) {
s[0] = "seekload.net" fmt.Printf("%T\n",s) fmt.Println(s)}func main() {
slice := []string{
"Hello","World","Go"} change(slice...) fmt.Println(slice)}

[]string[seekload.net World Go][seekload.net World Go]

从结果可以看出,main()函数的切片已经改变了。

为什么会有这样的输出呢?代码第 9 行,使用了语法糖...并且将切片作为可变参数传入change()函数。如上面讨论的,如果使用了...,切片本身会作为参数直接传入,不会再创建一个新的切片。所以在change()函数中,第一个元素被替换成 ,会影响到main()函数的切片。

另外,我们也可以通过将数组转化成切片传递给可变参数函数。

func change(s ...string) {
s[0] = "seekload.net" fmt.Printf("%T\n",s) fmt.Println(s)}func main() {
arr := [3]string{
"Hello","World","Go"} change(arr[:]...) fmt.Println(arr)}

输出结果跟上面的例子是一样的。

其他

给大家列几种比较常见的写法:

func change(s ...string) {
fmt.Printf("%T\n",s) fmt.Println(s)}func main() {
slice1 := []string{
"Hello","World","Go"} slice2 := []string{
"Aa","Bb"} // 1、 change(append(slice1,"Again")...) // 2、 change(append(slice1,slice2...)...)}

输出:

[]string[Hello World Go Again][]string[Hello World Go Aa Bb]

希望这篇文章对你有用!

参考:

1、
2、Go 语言文档:、

转载地址:http://ybfnb.baihongyu.com/

你可能感兴趣的文章
MySQL主主模式
查看>>
MySQL错误代码
查看>>
MySQL binlog的三种模式
查看>>
MySQL利用binlog增量恢复数据库
查看>>
Tomcat多实例多应用
查看>>
Tomcat启动慢解决方法
查看>>
Tomca主配置文件详解
查看>>
Tomcat创建虚拟主机
查看>>
Tomcat集群
查看>>
Tomcat DeltaManager集群共享session
查看>>
Tomcat连接Apache之mod_proxy模块
查看>>
sersync+rsync数据同步
查看>>
使用com.aspose.words将word模板转为PDF文件时乱码解决方法
查看>>
Linux发送邮件
查看>>
YUM安装PHP5.6
查看>>
YUM源安装MySQL5.7
查看>>
Tomcat日志切割cronolog
查看>>
glibc-2.14安装
查看>>
升级openssl zlib版本 安装nginx
查看>>
ab压力测试
查看>>