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)
}
posted @ 2022-05-28 15:49  左扬  阅读(367)  评论(0编辑  收藏  举报
levels of contents