如果非必要,盡量不要在程序中使用閉包。
go函數可以是一個閉包。閉包是一個函數值,它引用了函數體之外的變量。這個函數可以對這個變量進行訪問和賦值。
展示一個例子
package main
import "fmt"
func adder() func(int) int {
sum := 0
return func(x int) int {
sum += x
return sum
}
}
func main() {
pos, neg := adder(), adder()
for i := 0; i < 10; i++ {
fmt.Println(
pos(i),
neg(-2*i),
)
}
}
運行結果
0 0
1 -2
3 -6
6 -12
10 -20
15 -30
21 -42
28 -56
36 -72
45 -90
函數 adder() 內 return 了一個函數值,這個函數值引用了外部的 sum ,形成了一個閉包。
是不是有點看不懂?
好吧,其實 pos(i) 的這個 i ,是給進了 return func(x int) int 里的 x 了。
我們修改一下上面的代碼,增加幾個輸出語句。然后再看看運行結果。
package main
import "fmt"
func adder() func(int) int {
sum := 0
fmt.Println("外邊的sum",sum)
return func(x int) int {
fmt.Print("里邊的x", x, " --> ")
sum += x
return sum
}
}
func main() {
pos, neg := adder(), adder()
for i := 0; i < 10; i++ {
fmt.Println(
pos(i),
neg(-2*i),
)
}
}
增加了輸出的運行結果
外邊的sum 0
外邊的sum 0
里邊的x0 --> 里邊的x0 --> 0 0
里邊的x1 --> 里邊的x-2 --> 1 -2
里邊的x2 --> 里邊的x-4 --> 3 -6
里邊的x3 --> 里邊的x-6 --> 6 -12
里邊的x4 --> 里邊的x-8 --> 10 -20
里邊的x5 --> 里邊的x-10 --> 15 -30
里邊的x6 --> 里邊的x-12 --> 21 -42
里邊的x7 --> 里邊的x-14 --> 28 -56
里邊的x8 --> 里邊的x-16 --> 36 -72
里邊的x9 --> 里邊的x-18 --> 45 -90
這次看明白了么?
外邊的 sum 那個位置只是被調用時執行了一次, pos 和 neg 每次循環給入的變量都在 return func(x int) int 內累加。外面的語句沒有再執行。
adder() 返回了 func(int) int
func(int) 返回了 int
于是最后那條語句就是打印出兩個整數來。
至于,為什么先打印出 2 條“里邊的”,之后才打印出 2 個整數。還記得 go 語言的棧么?就是這個原因了。后進先出,先要分別執行完 pos 和 neg ,才能執行 Println 這句了。