26. 函数闭包

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

你可能感兴趣的:(26. 函数闭包)