闭包
什么是闭包,我们先来用ruby
看个例子:
sum = 0
10.times{|n| sum += n}
print sum
其中{}
就是闭包的内容,代码看起来是不是很清爽与简单。
我们再来看看Python
写的闭包:
def addx(x):
return lambda y: x + y
add8 = addx(8)
print add8(100)
用Python写就没有那么好看。
闭包(Closure)是词法闭包(Lexical Closure)的简称。对闭包的具体定义有很多种说法,这些说法大体可以分为两类:
- 一种说法认为闭包是符合一定条件的函数,闭包是在其词法上下文中引用了自由变量的函数。
- 另一种说法认为闭包是由函数和与其相关的引用环境组合而成的实体。比如参考资源中就有这样的的定义:在实现深约束时,需要创建一个能显式表示引用环境的东西,并将它与相关的子程序捆绑在一起,这样捆绑起来的整体被称为闭包。
这两种定义在某种意义上是对立的,一个认为闭包是函数,另一个认为闭包是函数和引用环境组成的整体。虽然有些咬文嚼字,但可以肯定第二种说法更确切。闭包只是在形式和表现上像函数,但实际上不是函数。函数是一些可执行的代码,这些代码在函数被定义后就确定了,不会在执行时发生变化,所以一个函数只有一个实例。闭包在运行时可以有多个实例,不同的引用环境和相同的函数组合可以产生不同的实例。所谓引用环境是指在程序执行中的某个点所有处于活跃状态的约束所组成的集合。其中的约束是指一个变量的名字和其所代表的对象之间的联系。那么为什么要把引用环境与函数组合起来呢?这主要是因为在支持嵌套作用域的语言中,有时不能简单直接地确定函数的引用环境。
仿函数
什么是仿函数,我们先用C++来写个例子:
struct comparer {
bool operator()(int a, int b) const {
return a > b;
}
};
int main(int, char**) {
std::vector<int> vec;
std::sort(vec.begin(), vec.end(), comparer());
return 0;
}
函数(functor)之所以称为仿函数,是因为这是一种利用某些类对象支持operator()
的特性,来达到模拟函数调用效果的技术。从上面你也可以看出来,仿函数实现的内容其实就像动态语言闭包实现的方式差不多,形式不一样,效果是一样的。至于语言本质是什么,就让语言学家去争论吧。