闭包
目录

1. 概念

闭包(Closure)词法闭包(Lexical Closure)的简称。

一种说法认为闭包是由函数和与其相关的引用环境组合而成的实体。 在实现绑定(binding)时,需要创建一个能显式表示引用环境的东西,并将它与相关的子程序捆绑在一起,这样捆绑起来的整体被称为闭包。

实现闭包的语言一般具有这样的特性:

  • 函数是第一类型(First-class value),即函数可以作为另一个函数的返回值或参数,还可以作为一个变量的值。
  • 函数可以嵌套定义,即在一个函数内部可以定义另一个函数。
  • 可以捕捉引用环境,并把引用环境和函数代码组成一个可调用的实体。

在这样的语言里,函数可以作为返回值,也可以作为参数,但这两种情况的实质是相同的。

闭包按照词法作用域确定引用环境,这个引用环境是函数定义时的引用环境,并与代码组合成一个整体。 当把这个整体当作函数调用时,先把其中的引用环境覆盖到当前的引用环境上,然后执行具体代码,并在调用结束后恢复原来的引用环境。 这样就保证了函数定义和执行时的引用环境是相同的。 这种由引用环境与函数代码组成的实体就是闭包。

引用环境指的是自由变量的引用。 自由变量是在函数外部定义的变量,也称为上值(upvalue)

当一个函数中没有自由变量的时候,那这个函数就是普通的函数。 因此可以把函数看作闭包的一个特例。

借用一个非常好的说法来做个总结:对象是附有行为的数据,而闭包是附有数据的行为。

2. 实现

Lua
function make_counter()
local count = 0
return function ()
count = count + 1
return count
end
end

c1 = make_counter()
c2 = make_counter()

print(c1())
print(c1())
print(c2())
Python

在Python2中,闭包不能访问外部函数中不可变类型的局部变量。

Python3:

def make_counter():
count = 0
def inc_count():
nonlocal count
count += 1
return count
return inc_count

c1 = make_counter()
c2 = make_counter()

print(c1())
print(c1())
print(c2())
Lisp
(defun make-counter ()
(let ((count 0))
#'(lambda ()
(setf count (1+ count)))))

(defparameter c1 (make-counter))
(defparameter c2 (make-counter))

(print (funcall c1))
(print (funcall c1))
(print (funcall c2))

3. 应用

加强模块化
抽象
简化代码

参考

发表评论