闭包的思想

doob_9117 · · 135 次点击 · · 开始浏览    

思考一个问题:
如何能够在运行的时候控制或者改变一个函数对于输入的行为?
比如在一个函数外部修改一个变量就能改变这个函数的行为?

于是一个称之为闭包的东西出现了。
闭包:函数和引用的外部变量一起构成一个闭包。

✳注意:如果没有上述目的,不要引用函数外部的变量。把它作为参数传入你的函数。否则你很有可能因此引入意想不到的bug。

如何实现闭包?
下面是golang的实现

以下引自https://hitzhangjie.github.io/jekyll/update/2018/05/19/golang-function-closure%E5%AE%9E%E7%8E%B0%E6%9C%BA%E5%88%B6.html

  1. 假如闭包定义后立即被调用 因为只会被使用一次,所以应该力图避免闭包对象的内存分配操作,那怎么优化一下呢,以下面的示例代码为例。
func(a int) {
    println(byval)
    byref++
}(42)

上面的闭包将被转换为简单函数调用的形式:

func(byval int, &byref *int, a int) {
    println(byval)
    (*&byref)++
}(byval, &byref, 42)

注意看函数原型的变化,原来闭包里面捕获的变量都被转换成了通过函数参数来供值:

因为println操作不涉及对byval变量的修改操作,所以是按值捕获;
而byref++涉及到对捕获变量的修改,所以是按引用捕获,对于按引用捕获的变量会进行特殊处理,golang编译器会在编译时将按引用捕获的变量名byref转换成“&byref”,同时将其类型转换成pointer类型,捕获变量对应的写操作也会转换为通过pointer来操作。
2) 假如闭包定以后并不是立即调用 闭包定义后不是立即使用,而是后续调用,这种情况下同一个闭包可能调用多次,这种情况下就需要创建闭包对象,如何实现呢?

如果变量是按值捕获,并且该变量占用存储空间小于2*sizeof(int),那么就通过在函数体内创建局部变量的形式来shadow捕获的变量,相比于通过引用捕获,这么做的好处应该是考虑到减少引用数量、减少逃逸分析相关的计算。
如果变量是按引用捕获,或者按值捕获但是捕获的变量占用存储空间较大(拷贝到本地做局部变量代价太大),这种情况下就将捕获的变量var转换成pointer类型的“&var”,并在函数prologue阶段将其初始化为捕获变量的值。

本文来自:简书

感谢作者:doob_9117

查看原文:闭包的思想

入群交流(和以上内容无关):Go中文网 QQ 交流群:798786647 或加微信入微信群:274768166 备注:入群;关注公众号:Go语言中文网

135 次点击  
加入收藏 微博
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传