相信“闭包”大家都听过,但到底什么是闭包,未必你就能够清晰的讲出来!那么这一节,就是解答这个疑问的。
一、何为闭包?
闭包(Closure)是由函数及其相关引用环境组合而成的实体(即:闭包=函数+引用环境)。或者另外一种比较常见的说法:闭包,是引用了自由变量的函数。
“官方定义”:
所谓“闭包”,指的是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分。
支持闭包的编程语言非常多,目前在JavaScript、Go、PHP、Scala、Scheme、Common Lisp、Smalltalk、Groovy、Ruby、 Python、Lua、objective c、Swift 以及Java8以上等语言中都能找到对闭包不同程度的支持。
看个最常见的闭包例子(JavaScript):
上面的代码创建了闭包,a函数返回了b函数,c指向了函数b,执行c()会显示i的值,所以,当函数a内的函数b被外面的变量引用时,就创建了一个闭包。因为闭包的存在,。a中的变量i始终存在,因为闭包使得垃圾回收机制GC不会收回a函数占用的资源。
c()跟c2()引用的是不同的环境,即引用的i变量不是一个。函数a()每进入一次,就形成了一个新的环境,对应的闭包中,函数都是同一个函数,环境却是引用不同的环境。
二、GO的闭包
Go语言当然也是支持闭包的,还是以上面的例子为例,改成Go语言版本的:
func a() func() int {
i := 0
b := func() int {
i++
fmt.Println(i)
return i
}
return b
}
func main() {
c := a()
c()
c()
c()
a() //不会输出i
}
//输出结果
1
2
3
闭包复制的是原对象指针,这就很容易解释延迟引用现象。看下面的示例:
x := 1
f := func() {
println(x)
}
x = 2
x = 3
f() // 3
因为闭包对外层词法域变量是引用的,所以这段代码会输出 3。可以想象 f 中保存着 x 的地址,它使用 x 时会直接解引用,所以 x 的值改变了会导致 f 解引用得到的值也会改变。
关于循环闭包引用的时候有一个比较常见的“坑”,大家可以移步这里详细了解: 代码块和作用域 Part 3。
Go闭包的内容就总结到这里,你都Get了吧?