Part 12 变参函数

欢迎来到 Golang教程系列的第12部分

什么是变参函数?

变参函数是一个可以接受参数数量可变的函数。

语法

如果一个函数的最后一个参数是以 ...T 为标记,则该函数的最后一个参数可以接受任何数量类型为 T 的参数。

请注意,一个函数仅最后一个参数允许参数可变

示例和理解变参函数如何工作

你是否想过被用来 append 变量到一个 sliceappend 函数是如何接受任意数目的参数。是因为经是一个变参函数

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的类型等价于 []int 即 整数切片。
可变参数函数的工作方式是将传递的参数的可变数量转换为可变参数类型的新切片。例如在上面程序的 22 行,find 函数的可变参数是 89,90,95。find函数期望一个 int 类型的可变参数,此后这三个参数将被编译器转换为一个 int 类型的切片[]int{89,90,95} 然后它将被传给 find 函数。

在第10行,for 循环将在遍历 nums 切片如果它在切片中出现,打印 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 是一个 nil 切片,长度和容量都是0.

给变参函数传入一个切片

让我们传入一个切片给变参函数并从下面的示例中提出会发生什么。

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
那么是否有一种方式可以给可变参数传递一个切片呢?答案当然是肯定的。

有一个语法糖可以被用来给变参函数传递一个切片。你必须将切片以 ... 为后缀,如果这样做后,切片会被直接传递给函数而不创建一个新的切片。

在上面的程序中,如果你使用 find(89, nums...) 替换23行的 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)
}

我会把它作为练习让你弄清楚上面的程序是如何工作的:).
这些是变参函数,感谢阅读,请留下您宝贵的反馈和意见。

下一个教程 Maps

原文

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值