Golang学习实战笔记-基础 > golang底层实现原理
golang内存逃逸和闭包实现的原理

 Golang的闭包原理

6.3.1匿名函数

所谓匿名函数就是没有名字的函数,我们在golang的代码中经常看到,常见的匿名函数一般如下形式

//不带参数,a()输出1
a := func() {
    fmt.Println(1)
}
//带参数a(1)输出1
b := func(arg int) {
    fmt.Println(arg)
}
//带返回值,c()的返回值为5
c := func() int {
    fmt.Println(4)
    return 5
}

我们先列出来这几种函数,为我们接下来看闭包打下一点基础

6.3.2 golang的闭包

我们先不给闭包下定义,我们先看下现象

package main

import "fmt"

func A() func(int) int {
    sum := 0
    return func(bb int) int {
        sum += bb
        fmt.Println("bb=", bb, "\tsum=", sum)
        return sum
    }
}

func main() {
    a := A()
    a(0)
    a(1)
    a(5)
}

看下运行的结果

我们看到一个奇怪的现象,sum的值貌似被累加了,为什么呢?这里其实就是形成了一个闭包,当创建a函数的时候,A函数把sum组装给了这个返回函数,组装进去的是它的引用,所以引起了累加现象,另外我们从逃逸分析方面验证下

看到没有,装载进a函数的事sum的引用,并且逃逸到了堆上,所以在A函数执行完之后,并不会释放掉sum。 另外我们注意掉貌似bb也被逃逸了啊,为什么它没有被累加呢,仔细看我们的bb是返回的函数a的参数穿进去的,是值传递喔。 我们继续看如下的代码

package main

import "fmt"

func A() func(int) int {
    sum := 0
    return func(bb int) int {
        sum += bb
        fmt.Println("bb=", bb, "\tsum=", sum)
        return sum
    }
}

func main() {
    a := A()
    c := A()
    a(0)
    a(5)
    c(10)
    c(20)
}

哟,看起来不对啊,sum没有被四次累加啊,看下逃逸分析

还是发现不了啊,难道不对?其实仔细向下,我们调用了两次A函数,sum变量是在A函数中被创建的,所以a函数的sum的引用与c函数中的sum的引用必然不是一个啊,所以这也就是它们各自行程了自己的闭包。

参考: https://zhuanlan.zhihu.com/p/53928921