闭包
在函数编程中经常用到闭包,闭包是什?它是怎么产生的及用来解决什么问题呢"color: #ff0000">Go语言中的闭包
先看一个demo:
func f(i int) func() int { return func() int { i++ return i } }
函数f返回了一个函数,返回的这个函数就是一个闭包。这个函数中本身是没有定义变量i的,而是引用了它所在的环境(函数f)中的变量i。
我们再看一下效果:
c1 := f(0) c2 := f(0) c1() // reference to i, i = 0, return 1 c2() // reference to another i, i = 0, return 1
c1跟c2引用的是不同的环境,在调用i++时修改的不是同一个i,因此两次的输出都是1。函数f每进入一次,就形成了一个新的环境,对应的闭包中,函数都是同一个函数,环境却是引用不同的环境。
变量i是函数f中的局部变量,假设这个变量是在函数f的栈中分配的,是不可以的。因为函数f返回以后,对应的栈就失效了,f返回的那个函数中变量i就引用一个失效的位置了。所以闭包的环境中引用的变量不能够在栈上分配。
escape analyze
在继续研究闭包的实现之前,先看一看Go的一个语言特性:
func f() *Cursor { var c Cursor c.X = 500 noinline() return &c }
Cursor是一个结构体,这种写法在C语言中是不允许的,因为变量c是在栈上分配的,当函数f返回后c的空间就失效了。但是,在Go语言规范中有说明,这种写法在Go语言中合法的。语言会自动地识别出这种情况并在堆上分配c的内存,而不是函数f的栈上。
为了验证这一点,可以观察函数f生成的汇编代码:
MOVQ $type."".Cursor+0(SB),(SP) // 取变量c的类型,也就是Cursor PCDATA $0,$16 PCDATA $1,$0 CALL ,runtime.new(SB) // 调用new函数,相当于new(Cursor) PCDATA $0,$-1 MOVQ 8(SP),AX // 取c.X的地址放到AX寄存器 MOVQ $500,(AX) // 将AX存放的内存地址的值赋为500 MOVQ AX,"".~r0+24(FP) ADDQ $16,SP
识别出变量需要在堆上分配,是由编译器的一种叫escape analyze的技术实现的。
如果输入命令:
go build --gcflags=-m main.go
可以看到输出:
注意:最后两行,标识c逃逸了,被移动到堆中。escape analyze可以分析出变量的作用范围,这是对垃圾回收很重要的一项技术。
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流。
广告合作:本站广告合作请联系QQ:858582 申请时备注:广告合作(否则不回)
免责声明:本站资源来自互联网收集,仅供用于学习和交流,请遵循相关法律法规,本站一切资源不代表本站立场,如有侵权、后门、不妥请联系本站删除!
免责声明:本站资源来自互联网收集,仅供用于学习和交流,请遵循相关法律法规,本站一切资源不代表本站立场,如有侵权、后门、不妥请联系本站删除!
暂无评论...
更新日志
2024年05月20日
2024年05月20日
- 张琍敏1978-雪中莲[台湾复刻版][WAV+CUE]
- 叶蕴仪1993-睡美人[日本版][WAV+CUE]
- 夜晚助兴音乐-群星《新时代床头音乐-性能量》2CD[WAV]
- 24K德国HD金碟《历届奥斯卡获奖金曲》3CD[WAV整轨]
- 邰正宵《重燃爱恋 贰 Walk On》[FLAC/分轨][431.72MB]
- 苏文劭《雨停出来走走》[320K/MP3][81.11MB]
- 苏文劭《雨停出来走走》[FLAC/分轨][210.76MB]
- 群星《2024好听新歌04》十倍音质WAV分轨
- 陈宁《弹指之间HQ》头版限量[低速原抓WAV+CUE]
- 陈宁《故人还》HQCDII限量签名版[低速原抓WAV+CUE]
- 苏文劭《春曲(Lessons)》[320K/MP3][39.8MB]
- 苏文劭《春曲(Lessons)》[FLAC/分轨][97.78MB]
- 群星《2006香港高级视听展原音精选 SACD》[ISO][2G]
- 张琍敏1977-枫林小雨[台湾复刻版][WAV+CUE]
- 林一峰2014-COOKINGMUSIC[香港首版][WAV+CUE]