一个 lambda(或closure) 封装了函数指针和变量。这就是为什么在 C# 中,您可以执行以下操作:
int lessThan = 100;
Func<int, bool> lessThanTest = delegate(int i) {
return i < lessThan;
};
我在那里使用了一个匿名委托作为闭包(它的语法比 lambda 等价物更清晰、更接近 C),它将 lessThan(堆栈变量)捕获到闭包中。当闭包被评估时,lessThan(其堆栈帧可能已被破坏)将继续被引用。如果我更改 lessThan,那么我会更改比较:
int lessThan = 100;
Func<int, bool> lessThanTest = delegate(int i) {
return i < lessThan;
};
lessThanTest(99); // returns true
lessThan = 10;
lessThanTest(99); // returns false
在 C 语言中,这是非法的:
BOOL (*lessThanTest)(int);
int lessThan = 100;
lessThanTest = &LessThan;
BOOL LessThan(int i) {
return i < lessThan; // compile error - lessThan is not in scope
}
虽然我可以定义一个带有 2 个参数的函数指针:
int lessThan = 100;
BOOL (*lessThanTest)(int, int);
lessThanTest = &LessThan;
lessThanTest(99, lessThan); // returns true
lessThan = 10;
lessThanTest(100, lessThan); // returns false
BOOL LessThan(int i, int lessThan) {
return i < lessThan;
}
但是,现在我在评估它时必须传递两个参数。如果我希望将此函数指针传递给 lessThan 不在范围内的另一个函数,我要么必须通过将其传递给链中的每个函数来手动保持其活动状态,要么将其提升为全局函数。
尽管大多数支持闭包的主流语言都使用匿名函数,但对此没有任何要求。你可以有没有匿名函数的闭包,也可以有没有闭包的匿名函数。
总结:闭包是函数指针+捕获变量的组合。