Go从入门到精通——函数——可变参数——参数数量不固定的函数形式
可变参数——参数数量不固定的函数形式
Go 语言支持可变参数特性,函数声明和调用时没有固定数量的参数,同时也提供了一套方法进行可变参数的多级传递。
Go 语言的可变参数格式如下:
func 函数名(固定参数列表, v...T)(返回参数列表){
函数体
}
特性如下:
- 可变参数一般被放置在函数列表的末尾,前面是固定参数列表,当没有固定参数时,所有变量就将是可变参数。
- v为可变参数变量,类型为 []T,也就是拥有多个 T 元素的 T 类型的切片, v 和 T 之间由 "..." 即 3 个点组成。
- T 为可变参数的类型,当 T 为 interface{}时,传入的可以是任意类型。
一、fmt 包中的例子
可变参数有两种形式:所有参数都是可变参数的形式,如 fmt.Println,以及部分是可变参数的形式,如 fmt.Printf,可变参数只能出现在参数的后半部分,因此不可变的参数只能放在参数的前半部分。
1、所有参数都是可变参数:fmt.Println (go version go1.18.1 windows/amd64)
// Println formats using the default formats for its operands and writes to standard output.
// Spaces are always added between operands and a newline is appended.
// It returns the number of bytes written and any write error encountered.
func Println(a ...any) (n int, err error) {
return Fprintln(os.Stdout, a...)
}
fmt.Println 在使用时,传入的值类型不受限制,例如:
fmt.Println(5,"Hello", &struct{a int}{1},true)
2. 部分参数是可变参数:fmt.Printf (go version go1.18.1 windows/amd64)
fmt.Printf 的第一个参数为参数列表,后面的参数是可变参数,fmt.Printf 函数的格式如下:
// Printf formats according to a format specifier and writes to standard output.
// It returns the number of bytes written and any write error encountered.
func Printf(format string, a ...any) (n int, err error) {
return Fprintf(os.Stdout, format, a...)
}
fmt.Printf()函数在调用时,第一个函数始终必须传入字符串,对应参数是 format,后面的参数变量可以变化,使用时候,代码如下:
fmt.Printf("pure string\n")
fmt.Printf("value: %v %f\n", true, math.Pi)
二、遍历可变参数列表——获取每一个参数的值
可变参数列表的数量不固定,传入的参数是一个切片。如果需要获得每一个参数的具体值时,可以对可变参数变量进行遍历。
package main
import (
"bytes"
"fmt"
)
//定义一个函数,参数数量为 0~n,类型约束为字符串
func joinStrings(slist ...string) string {
//定义一个字节缓冲,快速地连接字符串
var b bytes.Buffer
//遍历可变参数列表 slist,类型为 []string
for _, s := range slist {
//将遍历出的字符串连续写入字节数组
b.WriteString(s)
}
//将连接好的字节数组转换为字符串输出
return b.String()
}
func main() {
//输入3个字符串,将他们形成一个字符串
fmt.Println(joinStrings("ping", "and", "rat"))
fmt.Println(joinStrings("我", "爱", "中国"))
}
三、获得可变参数类型——获得每一个参数的类型
当可变参数为 interface{}类型时,可以传入任何类型的值。此时,如果需要获得变量的类型,可以通过 switch 类型分支获得变量的类型。
下面演示将一系列不同类型的值传入 printTypeValue()函数,该函数将分别为不同的参数打印它们的值和类型的详细描述。
package main
import (
"bytes"
"fmt"
)
func printTypeValue(slist ...interface{}) string {
//字节缓冲作为快速字符串连接
var b bytes.Buffer
//遍历参数
for _, s := range slist {
//将 interace{} 类型格式化为字符串
str := fmt.Sprintf("%v", s)
//类型的字符串描述
var typeString string
//对 s 进行类型断言
switch s.(type) {
case bool:
typeString = "bool"
case string:
typeString = "string"
case int:
typeString = "int"
}
//写值字符串前缀
b.WriteString("value: ")
//写入值
b.WriteString(str)
//写类型前缀
b.WriteString(" type: ")
//写类型字符串
b.WriteString(typeString)
//写入换行符
b.WriteString("\n")
}
return b.String()
}
func main() {
//将不同类型的变量通过 printTypeValue() 打印出来
fmt.Println(printTypeValue(100, "str", true))
}
代码运行结果:
Starting: D:\go-testfiles\bin\dlv.exe dap --check-go-version=false --listen=127.0.0.1:52207 from d:\go-testfiles
DAP server listening at: 127.0.0.1:52207
Type 'dlv help' for list of commands.
value: 100 type: int
value: str type: string
value: true type: bool
Process 9212 has exited with status 0
Detaching
dlv dap (12820) exited with code: 0
四、在多个可变参数函数中传递参数
可变参数变量是一个包含所有参数的切片,如果要在多个可变参数中传递参数,可以在传递时在可变参数变量中默认添加 "...",将切片中的元素进行传递,而不是传递可变参数变量本身。
package main
import "fmt"
func rawPrint(rawList ...interface{}) {
//遍历可变参数切片
for _, a := range rawList {
//打印参数
fmt.Println(a)
}
}
//打印函数封装
func print(slist ...interface{}) {
//将slist可变参数切片完整传递给下一个函数
rawPrint(slist...)
}
func main() {
print(1, 2, 3)
}