“闭包”这个词看起来很熟悉,在编程书中经常看见,但是我好像从来没真正理解这是个啥意思。今天查了很多资料,决定弄清楚这个词的含义。

记得在大学的离散数学的集合论中就见过“闭包”这个词,这个词也确实是最先出现在数学中的。离散数学中,如果对一个集合的每个成员进行某种运算,生成的结果仍然是这个集合的成员,则称该集合在某个运算下闭包。例如,整数集合在减法运算下构成闭包;但是自然数在减法运算下不构成闭包。因为自然数相减可能得到负数,负数就不再是自然数了。

那“闭包”这个词在编程语言中的含义是什么呢?比如,在Ruby语言中很多人称block, lambda和Proc为闭包,其实就是一个匿名函数,传入了外部环境的参数。这个理解到底是不是正确呢?来看看wiki的详细解释。

In programming languages, a closure (also lexical closure or function closure) is a function or reference to a function together with a referencing environment—a table storing a reference to each of the non-local variables (also called free variables or upvalues) of that function.[1] A closure—unlike a plain function pointer—allows a function to access those non-local variables even when invoked outside its immediate lexical scope.

从上面的引用能看出closure其实是带着自己scope去其他地方的fucntion,这个scope本来是访问不到的。因为函数作为头等元素,可以把函数作为返回值,或者当作参数传入其他函数,这样也把函数的scope传递过去了。举个最简单的Ruby的lambda的例子。

def compare_property(shape1, shape2, property)
  attr1 = property.call(shape1)
  attr2 = property.call(shape2)
  if attr1 > attr2
    1
  elsif attr1 == attr2
    0
  else
    -1
  end
end

def compare
  property = lambda{|shape| shape[:area]}

  shape1 = {:perimeter => 12, :area => 9}
  shape2 = {:perimeter => 18, :area => 8}
  compare_property(shape1, shape2, property)
end

puts compare()

上面的代码是要比较两个四边形大小,可以比较周长,也可以比较面积,比较的方式就通过一个名叫property的lambda传入。这个lambda其实是一个定义在compare函数的scope里面的,本来在compare_property的scope里面是不能访问的,但是通过把这个lambda作为一个参数传递给了compare_property函数,这个lambda的scope也被带去了。

在《SICP》这本书中还有另外一个含义。

In general, an operation for combining data objects satisfies the closure property if the results of combining things with that operation can themselves be combined using the same operation.

比如,一个数组还可以作为另一个数组的item,所以数组数据结构就是闭包的。

知乎还有人说在编译原理中也有closure这个术语,由于我已经忘了编译原理讲什么了(so sad),所以还是等补补编译原理再写完这里吧。

总的看来,各个地方“闭包”(closure)这个词的含义好像并没有什么关系,都是想表达闭(close)这个性质吧。