引入
有时候调用函数不确定要传几个参数——可能是 2 个,也可能是 20 个。Go 用 … 语法支持可变参数,函数内部把它当切片处理,调用时既可以逐个传参,也可以把切片展开传进去。
正文
定义
定义
可变参数允许函数接收任意数量的同类型参数。Go 用
…标记可变参数,函数内部以切片的方式访问这些参数。调用时可以用切片加…展开传入。
语法
// 声明可变参数
func 函数名(参数 ...类型) {
// 参数在函数内是切片
}
// 调用时逐个传参
函数名(1, 2, 3)
// 调用时展开切片
nums := []int{1, 2, 3}
函数名(nums...)例子
基本可变参数
func sum(nums ...int) int {
total := 0
for _, n := range nums {
total += n
}
return total
}
func main() {
fmt.Println(sum(1, 2, 3)) // 6
fmt.Println(sum(10, 20)) // 30
fmt.Println(sum()) // 0
}nums 在函数内部是 []int 类型,不传参数时是空切片。
固定参数 + 可变参数
func greet(prefix string, names ...string) {
for _, name := range names {
fmt.Println(prefix, name)
}
}
func main() {
greet("Hello,", "Alice", "Bob", "Carol")
// Hello, Alice
// Hello, Bob
// Hello, Carol
}可变参数只能放在最后一个,前面可以有固定参数。
切片展开传入
func sum(nums ...int) int {
total := 0
for _, n := range nums {
total += n
}
return total
}
func main() {
nums := []int{1, 2, 3, 4, 5}
result := sum(nums...)
fmt.Println(result) // 15
}已有的切片用 … 展开后传入,Go 不会创建新切片,直接复用原来的。
配合 fmt.Printf
func main() {
fmt.Println("a", "b", "c")
fmt.Printf("%d %d %d\n", 1, 2, 3)
}fmt.Println 和 fmt.Printf 本身就用了可变参数,所以能接收任意数量的值。
可变参数传递
func log(format string, args ...interface{}) {
fmt.Printf(format+"\n", args...)
}
func main() {
log("name: %s, age: %d", "Alice", 25)
}…interface{} 可以接收任意类型的参数,在函数内部再展开传给其他可变参数函数。
常见写法
| 写法 | 说明 |
|---|---|
func f(nums …int) | 可变参数声明 |
f(1, 2, 3) | 逐个传参调用 |
f(slice…) | 切片展开传入 |
func f(prefix string, nums …int) | 固定参数 + 可变参数 |
func f(args …interface{}) | 接收任意类型参数 |
特点
- 可变参数用
…声明,必须是最后一个参数 - 函数内部把可变参数当切片使用,可以
range遍历 - 不传可变参数时,切片为
nil(不是空切片) - 切片展开用
slice…,不会创建副本 …interface{}可以接收任意类型的参数- 一个函数只能有一个可变参数
理解
可变参数让函数的参数数量变得灵活,不用为了不同数量的输入写一堆重载。核心就是 … 在声明端表示”不定长”,在调用端表示”展开”。记住可变参数在函数内就是切片,所有切片操作都能直接用。
引出
函数学完了,接下来看一个和函数紧密相关的语句——defer。它延迟执行的特性在函数返回前才执行,是资源释放的好帮手。看看 Go defer 怎么用。