ラムダ (またはクロージャー) は、関数ポインターと変数の両方をカプセル化します。これが、C# で次のことができる理由です。
int lessThan = 100;
Func<int, bool> lessThanTest = delegate(int i) {
return i < lessThan;
};
私はそこで匿名デリゲートをクロージャーとして使用しました (構文はラムダに相当するものよりも少し明確で 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;
}
しかし、今は評価するときに 2 つの引数を渡さなければなりません。この関数ポインターを、lessThan がスコープ内にない別の関数に渡したい場合は、チェーン内の各関数に渡すか、グローバルに昇格して、手動で有効にしておく必要があります。
クロージャーをサポートするほとんどの主流言語は無名関数を使用しますが、その必要はありません。匿名関数のないクロージャーと、クロージャーのない匿名関数を持つことができます。
要約: クロージャは、関数ポインタ + キャプチャされた変数の組み合わせです。