如果非必要,尽量不要在程序中使用闭包。
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 这句了。