C語言中文網 目錄
首頁 > Go語言教程 > Go語言函數 閱讀:3,653

Go語言可變參數(變參函數)

所謂可變參數,是指參數數量不固定的函數形式。Go 語言支持可變參數特性,函數聲明和調用時沒有固定數量的參數,同時也提供了一套方法進行可變參數的多級傳遞。

Go 語言的可變參數格式如下:

func 函數名(固定參數列表, v … T)(返回參數列表){
    函數體
}

以下是對可變參數的函數的說明:
  • 可變參數一般被放置在函數列表的末尾,前面是固定參數列表,當沒有固定參數時,所有變量就將是可變參數。
  • v 為可變參數變量,類型為 []T,也就是擁有多個 T 元素的 T 類型切片,v 和 T 之間由...即3個點組成。
  • T 為可變參數的類型,當 T 為 interface{} 時,傳入的可以是任意類型。

fmt包中的例子

可變參數有兩種形式:所有參數都是可變參數的形式,如 fmt.Println,以及部分是可變參數的形式,如 fmt.Printf,可變參數只能出現在參數的后半部分,因此不可變的參數只能放在參數的前半部分。

1) 所有參數都是可變參數:fmt.Println

fmt.Println的函數聲明如下:
func Println(a ...interface{}) (n int, err error) {
    return Fprintln(os.Stdout, a...)
}
fmt.Println 在使用時,傳入的值類型不受限制,例如:
fmt.Println(5, "hello", &struct{ a int }{1}, true)

2) 部分參數是可變參數:fmt.Printf

fmt.Printf 的第一個參數為參數列表,后面的參數是可變參數,fmt.Printf 函數的格式如下:
func Printf(format string, a ...interface{}) (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("pig ", "and", " rat"))
    fmt.Println(joinStrings("hammer", " mom", " and", " hawk"))
}
代碼輸出如下:
pig and rat
hammer mom and hawk

代碼說明如下:
  • 第 8 行,定義了一個可變參數的函數,slist 的類型為 []string,每一個參數的類型是 string,也就是說,該函數只接受字符串類型作為參數。
  • 第 11 行,bytes.Buffer 在這個例子中的作用類似于 StringBuilder,可以高效地進行字符串連接操作。
  • 第 13 行,遍歷 slist 可變參數,s 為每個參數的值,類型為 string。
  • 第 15 行,將每一個傳入參數放到 bytes.Buffer 中。
  • 第 19 行,將 bytes.Buffer 中的數據轉換為字符串作為函數返回值返回。
  • 第 24 行,輸入 3 個字符串,使用 joinStrings() 函數將參數連接為字符串輸出。
  • 第 25 行,輸入 4 個字符串,連接后輸出。

如果要獲取可變參數的數量,可以使用 len() 函數對可變參數變量對應的切片進行求長度操作,以獲得可變參數數量。

獲得可變參數類型——獲得每一個參數的類型

當可變參數為 interface{} 類型時,可以傳入任何類型的值。此時,如果需要獲得變量的類型,可以通過 switch 類型分支獲得變量的類型。下面的代碼演示將一系列不同類型的值傳入 printTypeValue() 函數,該函數將分別為不同的參數打印它們的值和類型的詳細描述。

打印類型及值:
package main

import (
    "bytes"
    "fmt"
)

func printTypeValue(slist ...interface{}) string {

    // 字節緩沖作為快速字符串連接
    var b bytes.Buffer

    // 遍歷參數
    for _, s := range slist {

        // 將interface{}類型格式化為字符串
        str := fmt.Sprintf("%v", s)

        // 類型的字符串描述
        var typeString string

        // 對s進行類型斷言
        switch s.(type) {
        case bool:    // 當s為布爾類型時
            typeString = "bool"
        case string:    // 當s為字符串類型時
            typeString = "string"
        case int:    // 當s為整型類型時
            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))
}
代碼輸出如下:
value: 100 type: int
value: str type: string
value: true type: bool

代碼說明如下:
  • 第 8 行,printTypeValue() 輸入不同類型的值并輸出類型和值描述。
  • 第 11 行,bytes.Buffer 字節緩沖作為快速字符串連接。
  • 第 14 行,遍歷 slist 的每一個元素,類型為 interface{}。
  • 第 17 行,使用 fmt.Sprintf 配合%v動詞,可以將 interface{} 格式的任意值轉為字符串。
  • 第 20 行,聲明一個字符串,作為變量的類型名。
  • 第 23 行,switch s.(type) 可以對 interface{} 類型進行類型斷言,也就是判斷變量的實際類型。
  • 第 24~29 行為 s 變量可能的類型,將每種類型的對應類型字符串賦值到 typeString 中。
  • 第 33~42 行為寫輸出格式的過程。

在多個可變參數函數中傳遞參數

可變參數變量是一個包含所有參數的切片,如果要在多個可變參數中傳遞參數,可以在傳遞時在可變參數變量中默認添加...,將切片中的元素進行傳遞,而不是傳遞可變參數變量本身。

下面的例子模擬 print() 函數及實際調用的 rawPrint() 函數,兩個函數都擁有可變參數,需要將參數從 print 傳遞到 rawPrint 中。

可變參數傳遞:
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)
}
代碼輸出如下:
1
2
3

對代碼的說明:
  • 第 9~13 行,遍歷 rawPrint() 的參數列表 rawList 并打印。
  • 第 20 行,將變量在 print 的可變參數列表中添加...后傳遞給 rawPrint()。
  • 第 25 行,傳入 1、2、3 這 3 個整型值進行打印。

如果嘗試將第 20 行修改為:
rawPrint("fmt", slist)
再次執行代碼,將輸出:
[1 2 3]

此時,slist(類型為 []interface{})將被作為一個整體傳入 rawPrint(),rawPrint() 函數中遍歷的變量也就是 slist 的切片值。

可變參數使用...進行傳遞與切片間使用 append 連接是同一個特性。

精美而實用的網站,提供C語言C++STLLinuxShellJavaGo語言等教程,以及socketGCCviSwing設計模式JSP等專題。

Copyright ?2011-2018 biancheng.net, 陜ICP備15000209號

底部Logo