思考一个问题:
如何能够在运行的时候控制或者改变一个函数对于输入的行为?
比如在一个函数外部修改一个变量就能改变这个函数的行为?
于是一个称之为闭包的东西出现了。
闭包:函数和引用的外部变量一起构成一个闭包。
✳注意:如果没有上述目的,不要引用函数外部的变量。把它作为参数传入你的函数。否则你很有可能因此引入意想不到的bug。
如何实现闭包?
下面是golang的实现
- 假如闭包定义后立即被调用 因为只会被使用一次,所以应该力图避免闭包对象的内存分配操作,那怎么优化一下呢,以下面的示例代码为例。
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阶段将其初始化为捕获变量的值。
有疑问加站长微信联系(非本文作者)