闭包是在其词法上下文中引用了自由变量的函数。或者说是函数和其引用的环境的组合体。
func test(x int) func() {
    return func() {
        println(x)
    }
}
func main() {
    f := test(123)
    f()
}
输出:
123
如上边案例:test 返回的匿名函数会引用上下文环境变量x。当该函数在main中执行时,它依然可以正确读取x的值,这种现象称作闭包。
1.闭包的延迟求值特性
func test() []func()  {
    var s []func()
    for i := 0; i<2; i++ {
        s = append(s, func() {    //将多个匿名函数添加到列表
            println(&i, i)
        })
    }
    return s          //返回匿名函数列表
}
func main() {
    for _, f := range test() {   //迭代执行所有匿名函数
        f()
    }
}
输出:
0xc000014078 2
0xc000014078 2
我们可以看出输出输出结果并不是我们想象中的样子,因为,for循环复用局部变量i,那么每次添加的匿名函数引用的自然是同一变量。添加操作仅仅是将匿名函数放入列表,并未执行。因此当main函数执行这些函数时,它们读取的是环境变量i最后一次循环的值。
那么有什么解决方式么?可以这样,每次用不同的环境变量或参数复制,让各自闭包的环境各不相同。
改造下:
func test() []func()  {
    var s []func()
    for i := 0; i<2; i++ {
        x := i            //每次循环都重新定义
        s = append(s, func() {
            println(&x, x)
        })
    }
    return s
}
func main() {
    for _, f := range test() {
        f()
    }
}
输出:
0xc000014078 0
0xc000014090 1