2
2
========================
3
3
4
4
上一节:[ 第十一篇 数组和切片] ( /docs/golang_tutorial_11.md )
5
- 下一节:[ 第十三篇 包 ] ( /docs/golang_tutorial_13.md )
5
+ 下一节:[ 第十三篇 Map ] ( /docs/golang_tutorial_13.md )
6
6
7
7
这是本Golang系列教程的第12篇。
8
8
9
9
## 什么是变参函数?
10
10
11
- 变参函数是指可以接受可变数量的参数的函数 。
11
+ 变参函数是指可以接收可变数量的参数的函数 。
12
12
13
- ## 语法?
13
+ 如果一个函数的最后一个参数由 ` ...T ` 表示,则表示该函数可以接收任意数量的类型为 T 的参数。
14
14
15
- 如果一个函数的最后一个参数由 ` ...T ` 表示,则表示该函数可以接受任意数量的类型为 T 的参数 。
15
+ 请注意只有函数的最后一个参数才能指定为可变参数 。
16
16
17
- 请注意只有函数的最后一个参数才能指定为可变参数。
17
+ ## 语法
18
+
19
+ ``` golang
20
+ func hello (a int , b ...int ){
21
+ }
22
+ ```
23
+
24
+ 上述函数中,` b ` 就是一个可变参数,因为它的类型定义有 ` ... ` 前缀,因而可以接收任意数量的输入。以下语句可以用来调用这个变参函数:
25
+
26
+ ``` golang
27
+ hello (1 , 2 ) // passing one argument "2" to b
28
+ hello (5 , 6 , 7 , 8 , 9 ) // passing arguments "6, 7, 8 and 9" to b
29
+ ```
30
+
31
+ 第一行中,我们将 ` 2 ` 赋给了 ` b ` ;第二行中,我们将四个参数 ` 6, 7, 8, 9 ` 赋给了 ` b ` 。
32
+
33
+ 我们也可以选择不将参数传入变参函数(即:传入"零"个参数),例如:
34
+
35
+ ``` golang
36
+ hello (1 )
37
+ ```
38
+
39
+ 我们调用了 ` hello ` 函数,但是没有为 ` b ` 传入任何参数,这也是完全可以的。
40
+
41
+ 为什么变参函数中的可变参数必须在定义参数时放在最后?作为反例,我们来尝试将 ` hello ` 函数的第一个参数变成可变参数:
42
+
43
+ ``` golang
44
+ func hello (b ...int , a int ){
45
+ }
46
+ ```
47
+
48
+ 以上函数中,我们将无法为 ` a ` 传入参数, 因为无论我们在函数中传入多少参数,这些参数都会被赋给可变参数 ` b ` 。上述函数会出现编译错误:` syntax error: cannot use ... with non-final parameter b ` ,因此可变参数必须在定义参数时被放在最后。
18
49
19
50
## 案例
20
51
@@ -51,7 +82,9 @@ func main() {
51
82
}
52
83
```
53
84
54
- 上面的程序中,` func find(num int, nums ...int) ` 可以接受任意数量的参数。` ...int ` 在内部表示为切片。在这里 ` nums ` 的类型为 ` []int ` 。
85
+ 上面的程序中,` func find(num int, nums ...int) ` 可以为 ` nums ` 接收任意数量的参数。在函数内部,` nums ` 的类型为 ` []int ` ,即整数切片类型。
86
+
87
+ ** 变参函数会将可变数量的参数转换成相应类型的切片,例如上述函数的第22行,传入 ` find ` 函数的可变参数是 89,90,95,随后这些参数会被编译器转换为整数切片 ` []int{89, 90, 95} ` 然后被送入 ` find ` 函数内。**
55
88
56
89
第 10 行利用 ` range for ` 遍历 ` nums ` 切片,如果找到 num 则打印 num 所在位置,否则打印没有找到。
57
90
@@ -71,11 +104,52 @@ type of nums is []int
71
104
87 not found in []
72
105
```
73
106
74
- 在第 25 行,` find ` 只有一个参数。我们没有传递任何参数给 ` nums ...int ` 。这是合法的,(译者注:如果没有给可变参数传递任何值,则可变参数为 ` nil ` 切片),在这里 ` nums ` 是一个 ` nil ` 切片,长度和容量都是` 0 ` 。
107
+ 在第 25 行,` find ` 只有一个参数。我们没有传递任何参数给 ` nums ...int ` 。这是合法的,(译者注:如果没有给可变参数传递任何值,则可变参数为 ` nil ` 切片),在这里 ` nums ` 是一个 ` nil ` 切片,长度和容量都是` 0 ` 。
108
+
109
+ ## 切片 VS 可变参数
110
+
111
+ 我们现在肯定会想到一个问题:既然传入的可变参数被转换成了切片,那么我们为何不直接将一个切片传入函数中呢?我们将之前的函数用切片参数来改写:
112
+
113
+ ``` golang
114
+ package main
115
+
116
+ import (
117
+ " fmt"
118
+ )
119
+
120
+ func find (num int , nums []int ) {
121
+ fmt.Printf (" type of nums is %T \n " , nums)
122
+ found := false
123
+ for i , v := range nums {
124
+ if v == num {
125
+ fmt.Println (num, " found at index" , i, " in" , nums)
126
+ found = true
127
+ }
128
+ }
129
+ if !found {
130
+ fmt.Println (num, " not found in " , nums)
131
+ }
132
+ fmt.Printf (" \n " )
133
+ }
134
+ func main () {
135
+ find (89 , []int {89 , 90 , 95 })
136
+ find (45 , []int {56 , 67 , 45 , 90 , 109 })
137
+ find (78 , []int {38 , 56 , 98 })
138
+ find (87 , []int {})
139
+ }
140
+ ```
141
+
142
+ 用可变参数代替切片的优势如下:
143
+
144
+ 1 . 不用在每次调用函数时都创建一个新的切片。上述函数中,我们在第22、23、24、25行都创建了新的切片,如果使用变参函数,这些额外的切片创建就可以省略。
75
145
76
- ## 传递切片给可变参数
146
+ 2 . 在第25行,为了满足 ` find ` 函数的参数定义,我们创建了一个空的切片,在变参函数中,我们只需要写 ` find(87) ` 即可。
77
147
78
- 我们已经提到 ` ...T ` 在内部表示为类型是 ` []T ` 切片。如果真是这样,可以传递一个切片给可变参数吗?让我们从下面的例子中寻找答案:
148
+ 3 . 我(原文作者)认为带变参函数的程序比带切片的函数可读性强 :)
149
+
150
+ ## 将切片传入可变参数
151
+
152
+ 我们已经提到 ` ...T ` 在内部表示为类型是 ` []T ` 切片。如果真是这样,可以传递一个切片给可变参数吗?让我们从下面的例子中寻找答案:
79
153
80
154
``` golang
81
155
package main
@@ -104,9 +178,9 @@ func main() {
104
178
}
105
179
```
106
180
107
- 在第 23 行,我们没有将若干数量的参数传递给 ` find ` 的最后一个参数 , 而是传递了一个切片。这是非法的,我们不能传递一个切片给可变参数。上面的程序将报错:` main.go:23: cannot use nums (type []int) as type int in argument to find ` 。
181
+ 在第 23 行,我们没有将若干数量的参数传递给 ` find ` 函数的最后一个参数 , 而是传递了一个切片。这是非法的,我们不能传递一个切片给可变参数。上面的程序将报错:` main.go:23: cannot use nums (type []int) as type int in argument to find ` 。
108
182
109
- 这里有一个语法糖可以用来将切片传递给变参函数。可以在切片后面加 ` ... ` ,这样会将切片展开为其中的各个元素并将它们传递给变参函数。这样该程序将正常工作。
183
+ ** 有一个语法糖可以用来将切片传递给变参函数:在切片后面加 ` ... ` ,这样会将切片展开为其中的各个元素并将它们传递给变参函数,程序将正常工作。 **
110
184
111
185
上面的程序如果将第23行的 ` find(89, nums) ` 改为` find(89, nums...) ` ,程序将通过编译,并输出如下:
112
186
@@ -116,6 +190,3 @@ type of nums is []int
116
190
```
117
191
118
192
变参函数的介绍到此结束。感谢阅读。
119
-
120
- 上一节:[ 第十一篇 数组和切片] ( /docs/golang_tutorial_10.md )
121
- 下一节:[ 第十三篇 Map] ( /docs/golang_tutorial_12.md )
0 commit comments