當前位置:網站首頁>[11 Go語言基礎-可變參數函數]

[11 Go語言基礎-可變參數函數]

2021-08-19 20:45:32 劉較瘦丫

[11 Go語言基礎-可變參數函數]

可變參數函數

什麼是可變參數函數

可變參數函數是一種參數個數可變的函數。

語法

如果函數最後一個參數被記作 ...T ,這時函數可以接受任意個 T 類型參數作為最後一個參數。

請注意只有函數的最後一個參數才允許是可變的。

通過一些例子理解可變參數函數如何工作

你是否曾經想過 append 函數是如何將任意個參數值加入到切片中的。這樣 append 函數可以接受不同數量的參數。

func append(slice []Type, elems ...Type) []Type

上面是 append 函數的定義。在定義中 elems 是可變參數。這樣 append 函數可以接受可變化的參數。

讓我們創建一個我們自己的可變參數函數。我們將寫一段簡單的程序,在輸入的整數列錶裏查找某個整數是否存在。

package main

import (
    "fmt"
)

func find(num int, nums ...int) {
    fmt.Printf("type of nums is %T\n", nums)
    found := false
    for i, v := range nums {
        if v == num {
            fmt.Println(num, "found at index", i, "in", nums)
            found = true
        }
    }
    if !found {
        fmt.Println(num, "not found in ", nums)
    }
    fmt.Printf("\n")
}
func main() {
    find(89, 89, 90, 95)
    find(45, 56, 67, 45, 90, 109)
    find(78, 38, 56, 98)
    find(87)
}

在上面程序中 func find(num int, nums ...int) 中的 nums 可接受任意數量的參數。在 find 函數中,參數 nums 相當於一個整型切片。

可變參數函數的工作原理是把可變參數轉換為一個新的切片。以上面程序中的第 22 行為例,find 函數中的可變參數是 89,90,95 。 find 函數接受一個 int 類型的可變參數。因此這三個參數被編譯器轉換為一個 int 類型切片 int []int{89, 90, 95} 然後被傳入 find函數。

在第 10 行, for 循環遍曆 nums 切片,如果 num 在切片中,則打印 num 的比特置。如果 num 不在切片中,則打印提示未找到該數字。

上面代碼的輸出值如下,

type of nums is []int
89 found at index 0 in [89 90 95]

type of nums is []int
45 found at index 2 in [56 67 45 90 109]

type of nums is []int
78 not found in  [38 56 98]

type of nums is []int
87 not found in  []

在上面程序的第 25 行,find 函數僅有一個參數。我們沒有給可變參數 nums ...int 傳入任何參數。這也是合法的,在這種情况下 nums 是一個長度和容量為 0 的 nil 切片。

給可變參數函數傳入切片

下面例子中,我們給可變參數函數傳入一個切片,看看會發生什麼。

package main

import (
    "fmt"
)

func find(num int, nums ...int) {
    fmt.Printf("type of nums is %T\n", nums)
    found := false
    for i, v := range nums {
        if v == num {
            fmt.Println(num, "found at index", i, "in", nums)
            found = true
        }
    }
    if !found {
        fmt.Println(num, "not found in ", nums)
    }
    fmt.Printf("\n")
}
func main() {
    nums := []int{89, 90, 95}
    find(89, nums)
}

在第 23 行中,我們將一個切片傳給一個可變參數函數。

這種情况下無法通過編譯,編譯器報出錯誤 main.go:23: cannot use nums (type []int) as type int in argument to find

為什麼無法工作呢?原因很直接,find 函數的說明如下,

func find(num int, nums ...int)

由可變參數函數的定義可知,nums ...int 意味它可以接受 int 類型的可變參數。

在上面程序的第 23 行,nums 作為可變參數傳入 find 函數。前面我們知道,這些可變參數參數會被轉換為 int 類型切片然後在傳入 find 函數中。但是在這裏 nums 已經是一個 int 類型切片,編譯器試圖在 nums 基礎上再創建一個切片,像下面這樣

find(89, []int{nums})

這裏之所以會失敗是因為 nums 是一個 []int類型 而不是 int類型。

那麼有沒有辦法給可變參數函數傳入切片參數呢?答案是肯定的。

有一個可以直接將切片傳入可變參數函數的語法糖,你可以在在切片後加上 ... 後綴。如果這樣做,切片將直接傳入函數,不再創建新的切片

在上面的程序中,如果你將第 23 行的 find(89, nums) 替換為 find(89, nums...) ,程序將成功編譯並有如下輸出

type of nums is []int
89 found at index 0 in [89 90 95]

下面是完整的程序供您參考。

package main

import (
    "fmt"
)

func find(num int, nums ...int) {
    fmt.Printf("type of nums is %T\n", nums)
    found := false
    for i, v := range nums {
        if v == num {
            fmt.Println(num, "found at index", i, "in", nums)
            found = true
        }
    }
    if !found {
        fmt.Println(num, "not found in ", nums)
    }
    fmt.Printf("\n")
}
func main() {
    nums := []int{89, 90, 95}
    find(89, nums...)
}

不直觀的錯誤

當你修改可變參數函數中的切片時,請確保你知道你正在做什麼。

下面讓我們來看一個簡單的例子。

package main

import (
    "fmt"
)

func change(s ...string) {  
    s[0] = "Go"
}

func main() {
    welcome := []string{"hello", "world"}
    change(welcome...)
    fmt.Println(welcome)
}

你認為這段代碼將輸出什麼呢?如果你認為它輸出 [Go world] 。恭喜你!你已經理解了可變參數函數和切片。如果你猜錯了,那也不要緊,讓我來解釋下為什麼會有這樣的輸出。

在第 13 行,我們使用了語法糖 ... 並且將切片作為可變參數傳入 change 函數。

正如前面我們所討論的,如果使用了 ...welcome 切片本身會作為參數直接傳入,不需要再創建一個新的切片。這樣參數 welcome 將作為參數傳入 change 函數

change 函數中,切片的第一個元素被替換成 Go,這樣程序產生了下面的輸出值

[Go world]

這裏還有一個例子來理解可變參數函數。

package main

import (
    "fmt"
)

func change(s ...string) {
    s[0] = "Go"
    s = append(s, "playground")
    fmt.Println(s)
}

func main() {
    welcome := []string{"hello", "world"}
    change(welcome...)
    fmt.Println(welcome)
}


可變長參數(小練習)

package main

import "fmt"

// 可變長參數

func main() {
	//test2("11111","2")
	var a []string=[]string{"lqz","egon"}
	test2(a...)  // 把切片傳入

}

func test2(a ...string)  {  // a是切片
	fmt.Println(a)
	fmt.Println(a[1])
	fmt.Printf("%T",a)
	a=append(a,"lqz")
	fmt.Println(a)
}

版權聲明
本文為[劉較瘦丫]所創,轉載請帶上原文鏈接,感謝
https://cht.chowdera.com/2021/08/20210819204531930i.html

隨機推薦