闭包的定义
    闭包是由函数及其相关的引用环境组合而成的实体(即:闭包=函数+引用环境)。
    引用环境的定义
    在函数式语言中,当内嵌函数体内引用到体外的变量时,将会把定义时涉及到的引用环境和函数体打包成一个整体(闭包)返回。现在给出引用环境的定义就容易理解了:引用环境是指在程序执行中的某个点所有处于活跃状态的约束(一个变量的名字和其所代表的对象之间的联系)所组成的集合。闭包的使用和正常的函数调用没有区别。
    由于闭包把函数和运行时的引用环境打包成为一个新的整体,所以就解决了函数编程中的嵌套所引发的问题。当每次调用包含闭包的函数时都将返回一个新的闭包实例,这些实例之间是隔离的,分别包含调用时不同的引用环境现场。不同于函数,闭包在运行时可以有多个实例,不同的引用环境和相同的函数组合可以产生不同的实例。

    闭包与逃逸分析
    闭包可能会导致变量逃逸到堆上来延长变量的生命周期,给 GC 带来压力。
    15. 闭包分析 - 图1
    可以执行一下如下指令:
    go build -gcflags “-N -l -m” closure
    看下结果
    15. 闭包分析 - 图2
    闭包与外部函数的生命周期
    内函数对外函数的变量的修改,是对变量的引用。共享一个在堆上的变量。 变量被引用后,它所在的函数结束,这变量也不会马上被销毁。相当于变相延长了函数的生命周期。
    看个例子:
    func AntherExFunc(n int) func() {
    n++
    return func() {
    fmt.Println(n)
    }
    }

    func ExFunc(n int) func() {
    return func() {
    n++
    fmt.Println(n)
    }
    }

    func main() {
    myAnotherFunc:=AntherExFunc(20)
    fmt.Println(myAnotherFunc) //0x48e3d0 在这儿已经定义了n=20 ,然后执行++ 操作,所以是21 。
    myAnotherFunc() //21 后面对闭包的调用,没有对n执行加一操作,所以一直是21
    myAnotherFunc() //21

    1. myFunc:=ExFunc(10)<br /> fmt.Println(myFunc) //0x48e340 这儿定义了n 为10<br /> myFunc() //11 后面对闭包的调用,每次都对n进行加1操作。<br /> myFunc() //12

    }
    (3)通过for循环的案例分析闭包对引用环境中变量的调用问题
    func main() {
    s := []string{“a”, “b”, “c”}
    for , v := range s {
    go func() {
    fmt.Println(v)
    }()
    }
    time.Sleep(time.Second 1)
    }
    结果会是什么呢? a, b, c? 错了,结果是 c, c, c。为什么呢?
    这是因为for语句里面中闭包使用的v是外部的v变量,当执行完循环之后,v最终是c,所以输出了 c, c, c。 如果你去执行,有可能也不是这个结果。 输出这个结果的前提是“在主协程执行完for之后,定义的子协程 才开始执行,如果for过程中,子协程执行了,结果就可能不是c, c,c”。 输出的结果依赖于子协程执行时的那一刻,v是什么。
    *之前 这个地方留了个疑问,是否是主协程中有闭包时,应该会先把闭包定义好,先不执行,当主协程执行完之后,再执行闭包所在的协程,此时协程使用环境变量v???

    答案: 不是。
    看下面的程序便知:
    func main() {
    s := []string{“a”, “b”, “c”}
    for
    , v := range s {
    go func() {
    fmt.Println(v)
    }()
    time.Sleep(time.Second 3)
    }
    fmt.Println(“main routine”)
    time.Sleep(time.Second
    1) // 阻塞模式
    }
    此时输出的就是 a, b, c , main routine
    为什么这次有正常了呢? 这是因为在for循环中执行了sleep, 让每次for循环中新定义的子协程有时间执行,子协程执行时获取环境中的变量v, 那么每次就会是本次循环执行时变量v的实际值。
    如果想输出b, b, c 呢?可以看下面的代码:
    func main() {
    s := []string{“a”, “b”, “c”}
    for k, v := range s {
    go func() {
    fmt.Println(v)
    }()
    // 在执行到第二次时,sleep一会,此时已经定义的两个子协程得到执行,而此时的v为b
    if k == 1 {
    time.Sleep(time.Second 3)
    }
    }
    fmt.Println(“main routine”)
    time.Sleep(time.Second
    1) // 阻塞模式
    }
    最开始的for程序如果想输出a,b,c还有一种解决方法:
    只需要每次将变量v的拷贝传进函数即可,但此时就不是使用的上下文环境中的变量了。
    func main() {
    s := []string{“a”, “b”, “c”}
    for _, v := range s {
    go func(v string) {
    fmt.Println(v)
    }(v) //每次将变量 v 的拷贝传进函数
    }
    select {}
    }
    (4)当closure所在函数重新调用时,其closure是新的,其context引用的变量也是重新在heap定义过的。
    func main() {
    nextInt := intSeq()
    println(unsafe.Pointer(&nextInt))
    println(nextInt()) // 1
    println(nextInt()) // 2
    println(nextInt()) // 3

    1. newInts := intSeq()<br /> println(unsafe.Pointer(&newInts))<br /> println(newInts()) // 1

    }

    func intSeq() func() int {
    i := 0
    println(“closure init———————“)
    println(unsafe.Pointer(&i))
    return func() int {
    i += 1
    println(“in closure”)
    println(unsafe.Pointer(&i))
    return i
    }
    }
    看下结果:
    closure init——————— 0xc00001a068 0xc000042778 in closure 0xc00001a068 1 in closure 0xc00001a068 2 in closure 0xc00001a068 3 closure init——————— 0xc00001a080 0xc000042780 in closure 0xc00001a080 1
    5 延迟调用与闭包
    defer 调用会在当前函数执行结束前才被执行,这些调用被称为延迟调用 。defer 中使用匿名函数依然是一个闭包。
    package main

    import “fmt”

    func main() {
    x, y := 1, 2

    1. defer func(a int) { <br /> fmt.Printf("x:%d,y:%d\n", a, y) // y 为闭包引用<br /> }(x) // 复制 x 的值
    2. x += 100<br /> y += 100<br /> fmt.Println(x, y)<br />}<br />输出结果是<br />101 102 x:1,y:102