函数式编程之闭包

维基百科)中是这样定义闭包的:
在计算机科学中,闭包(英语:Closure),又称词法闭包(Lexical Closure)或函数闭包(function closures),是引用了自由变量的函数这个被引用的自由变量将和这个函数一同存在,即使已经离开了创造它的环境也不例外

这里有两点需要把握,自由变量和函数。则判断是不是闭包首先判断是不是函数,如果都不是函数那么肯定不是闭包,是函数再继续判断是否有自由变量。
自由变量就是这里的重点了。。。

个人简单粗暴的将自由变量理解为当前函数引用的外部变量

这里先举个例子简单感受下,看个golang代码:

1
2
3
4
5
6
func f(i int) func() int {
return func() int {
i++
return i
}
}

f是个function,此方法是返回一个function(由于f返回的function无法在外部访问,没有必要给他起名字,所以就直接返回一个匿名函数)。
其中变量i是f的参数,是f的局部变量,匿名函数在f的命名空间内,可以引用变量i,这个匿名函数就是一个闭包。

我们根据闭包的定义理解下这个f的返回值。

变量i是f的局部变量,正常情况下f执行结束之后i会被回收,会随着f的结束而消失。但是这里f返回的匿名函数引用了i,这个i就作为了这个匿名函数的外部变量,也就成了一个自由变量,此自由变量会与匿名函数一同存在,即使已经离开了创造它的环境也不例外,形成了一个实体,也就是闭包。

再看个代码,我们把定义扩展下,代码如下:

1
2
3
4
5
c1 := f(0)
c2 := f(0)
fmt.Println(c1()) // reference to i, i = 0, return 1
fmt.Println(c1()) // reference to i, i = 1, return 2
fmt.Println(c2()) // reference to another i, i = 0, return 1

如果你看过其它关于闭包的资料,你可能有这个印象,闭包运行时可以有多个实例
根据上面的代码解释下,
f是一个函数,函数是一些可执行的代码,这些代码在函数被定义后就确定了,不会在执行时发生变化,所以一个函数只有一个实例。f(0)返回一个闭包,c1和c2引用的i是f(0)传进去的0,c1和c2第一次执行时,自由变量都为0,执行结束在匿名函数内递增变为1,引用环境发生了变化,第二次执行c1时,闭包中的引用环境已经由i=0变为了i=1,所以经过递增变为了2。这里两次调用c1得到不通的结果,这也就是说闭包在运行时会根据不同的引用环境产生不通的实例。

所谓引用环境是指在程序执行中的某个点所处于活跃状态的约束所组成的集合。其中的约束是指一个变量的名字和其所代表的对象之间的联系。

参考1
参考2

您的肯定,是我装逼的最大的动力!