1. 程式人生 > 其它 >Go從入門到精通——函式——可變引數——引數數量不固定的函式形式

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)
}