9.6Go之函数之可变参数

9.6Go之函数之可变参数

可变参数的概念

概念:

可变参数是指:

  • 传入的参数类型可变

  • 传入的参数数量可变

传入参数数量可变

特点:

  • 以切片举例,通常我们指传入参数的值的数量可变

  • 在Go语言中提供了一种语法糖(syntactic sugar)...type这种语法对语言的功能并没有影响,能够增加程序的可读性,减少程序出错的可能。

    • 类型...type本质上是一个数组切片,也就是[]type,所以参数 args 可以用 for 循环来获得每个传入的参数。

示例:

package main

import "fmt"

func getValue(args ...int) {
for _, v := range args {
fmt.Printf("value is:%d ", v)
}
/*
这里的形参带了...会自动将数据类型转为数组类型使用切片的方式进行接收和打印
*/
}

/*
如果没有...的语法糖那么在实现的时候需要这样写
*/
func getValue2(args []int) {
for _, v := range args {
fmt.Printf("Value is:%d ", v)
}
}

func main() {
getValue(1,2,3,4,5)
   fmt.Println("##########")
//调用的时候传入的参数就必须是数组切片
getValue2([]int{5,4,3,2,1})
}

通常这种情况用于接收相同类型的参数,由于可变参数列表的数量不固定,传入的参数是一个切片,如果需要获得每一个参数的具体值时:

  • 对可变参数变量进行遍历

  • 将可变参数的内容进行拼接

使用bytes包下封装好的方法--->主要用到BufferWriteStringString方法

示例:

package main

import (
"bytes"
"fmt"
)

func jointString(slist ...string) string {
//定义变量--->这个变量相当于字符串拼接完成后的值--->这是一个字节数组
var b bytes.Buffer //Buffer是一个结构体,创建字节数组类型的变量

//循环获取形参数组里面的内容
for _, v := range slist {
//将遍历出的字符串连续写入字节数组
b.WriteString(v) //将每一个传入参数放到 bytes.Buffer 中
}

return b.String() //传入字节数组的指针,返回拼接后的字符串值
}

func main() {
//连续输入字符将它们拼接成一个字符串
fmt.Println(jointString("Jun", "is", "a", "handsome", "boy!"))
}
/*
要获取可变参数的数量,使用 len() 函数对可变参数变量对应的切求长度,获得可变参数数量
*/

传入参数类型、数量均可变

特点:

  • 要使传入参数的类型、数量均可变则需要采用interface{}

  • Go语言标准库中 fmt.Printf() 的函数原型:

    • func Printf(format string, args ...interface{}) {
         // ...
      }
      /*
      使用interface{}是类型安全的
      */

示例:

package main

import "fmt"

func parameters(args ...interface{}) {
for _, v := range args {
switch v.(type) {
case string:
fmt.Printf("Value is:%s ", v)
case int:
fmt.Printf("Value is:%d ", v)
case float32:
fmt.Printf("Value is:%f ", v)
case float64:
fmt.Printf("Value is:%f", v)
default:
fmt.Println("Unknow type!!!")
}
}
   /*
   首先:
   1、interface{}前必须+"...",否则会认为是单个值,不能进行循环
   2、switch的内容是v变量,该变量被声明为interface{}当中的每一个值
   3、通过.type类型去判断里面的值的类型然后进行相应的处理
   4、由进行的匿名循环看出,这些类型被内置定义成了一个类似切片的类型,所以才可以进行匿名循环
   */
   /*
   Go语言中的interface{}又比Java当中的inteface强大了很多。
   Java当中的interface是一个类型,能接收的对象是实现了该接口的类的对象
   Go当中的interface则不是
   */
}

func main() {
parameters(1,"JunkingBoy",3.1415)
}
/*
在传递参数的时候可以传递任意类型的参数
*/

由于上诉操作可变参数为 interface{} 类型,可以传入任何类型的值,下面将这些内容拼接成字符串并且打印出来:

package main

import (
"bytes"
"fmt"
)

func printTypeValue(slist ...interface{}) string {
//定义字节数组
var b bytes.Buffer
//定义一个描述类型的字符串
var valueType string

//循环获取interface{}当中的值
for _, s := range slist {
//定义一个写入的值的变量
str := fmt.Sprintf("%v", s) //注意这个方法是Sprintf不是Printf
       /*
       使用 fmt.Sprintf 配合%v动词,可以将 interface{} 格式的任意值转为字符串
       */
//判断值的类型
switch s.(type) {
case bool:
valueType = "bool"
case int:
valueType = "int"
case string:
valueType = "string"
default:
fmt.Println("Unknow value type!")
}
       /*
       switch s.(type) 可以对 interface{} 类型进行类型断言,判断变量的实际类型
       */

//分别写入字符串前缀、值、类型
b.WriteString("value is:")
b.WriteString(str + " ")
b.WriteString("type:")
b.WriteString(valueType)
b.WriteString(" ")
}

return b.String()
}

func main() {
fmt.Println(printTypeValue(100, "JunkingBoy", false))
}

在多个可变参数函数中传递参数--->将可变参数整体传递给下一个可变参数函数

特点:

  • 可变参数变量是一个包含所有参数的切片,要将这个含有可变参数的变量传递给下一个可变参数函数,在传递时给可变参数变量后面添加...,就可以将切片中的元素进行传递,而不是传递可变参数变量本身。

  • 传递可变参数中每一个参数元素本身而不是可变参数这个变量--->非常重要

示例:--->创建两个函数,将第二个函数的形参完整的传递给第一个函数,在第二个函数里面调用第一个函数(有点类似闭包但是却不是)

package main

import "fmt"

/*
第一个函数
*/
func rawPrint(slist ...interface{}) {
//遍历切片
for _, v := range slist {
//打印参数
fmt.Println(v)
}
}

/*
第二个函数,在内部调用第一个函数
*/
func print(slist ...interface{}) {
//将传入的形参元素完整的传递给第一个函数
rawPrint(slist...) //将变量在 print 的可变参数列表中添加...后传递给 rawPrint()。
   /*
   这个时候通过打印的结果可以看出slist类型不是作为一个整体传入rawPrint当中,而是逐个元素传入
   */
   rawPrint("fmt", slist) //此时,slist(类型为 []interface{})将被作为一个整体传入 rawPrint(),rawPrint() 函数中遍历的变量也就是 slist 的切片值。

}

func main() {
//外部调用第二个函数
print(1, "JunkingBoy", 2)
}

可变参数使用...进行传递与切片间使用 append 连接是同一个特性。

It's a lonely road!!!
原文地址:https://www.cnblogs.com/JunkingBoy/p/15235301.html