欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

golang教程之可变函数

程序员文章站 2022-06-26 12:53:52
...

可变函数

原文:https://golangbot.com/variadic-functions/

什么是可变函数?

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

语法

如果函数的最后一个参数用...表示,则该函数可以接受最后一个参数的任意数量的类型为T的参数。

请注意,只允许函数的最后一个参数为可变参数

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

你有没有想过用于向切片附加值的append函数如何接受任意数量的参数。 这是因为它具有可变功能。

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

以上是追加功能的定义。 在这个定义中,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,95find函数需要一个可变 int参数。 因此,这三个参数将由编译器转换为int [] int {89,90,95}类型的切片,然后它将被传递给find函数。

在第10行所示,for循环在nums切片上的range,并且如果它存在于切片中则打印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函数调用只有一个参数。我们还没有向variadic nums ... int参数传递任何参数。 这是完全合法的,在这种情况下,nums是一个长度和容量为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类型的可变数量的参数。

排队号码 在上面的程序中,nums作为可变参数传递给find函数。 正如我们已经讨论过的,这些可变参数将被转换为int类型的切片,因为find需要int型可变参数。 在这种情况下,nums已经是一个int切片,并且尝试使用nums创建new []int切片,即编译器尝试执行

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函数。

正如我们已经讨论的那样,如果使用了...,切片本身将作为参数传递,而不会创建新的切片。 因此欢迎将作为参数传递给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)
}