lambda表达式(以及程度,匿名函数)是否闭包?
我对闭包的理解是它们是被视为对象的函数,这似乎是匿名函数和Lambda表达式所做的准确表示。
将它们称为闭包是否正确?我知道由于lisp方言,闭包会产生(或变得流行),但它是否也是一般的编程术语?
感谢您提供的任何澄清!
答案 0 :(得分:104)
lambda可以使用闭包来实现,但它本身不一定是闭包。
closure是“与该函数的非局部变量的引用环境一起的函数。”。
当你创建一个使用在方法之外定义的变量的lambda表达式时,必须使用闭包来实现lambda。例如:
int i = 42;
Action lambda = () => { Console.WriteLine(i); };
在这种情况下,编译器生成的方法必须能够访问在完全不同的范围内定义的变量(i
)。为了使其工作,它生成的方法是“与引用环境一起工作” - 基本上,它创建了一个“闭包”来检索对变量的访问。
然而,这个lambda:
Action lambda2 = () => { Console.WriteLine("Foo"); }
不依赖于任何“引用环境”,因为它是一个完全包含的方法。在这种情况下,编译器会生成一个普通的静态方法,并且根本不涉及任何闭包。
在这两种情况下,lambda都会创建一个delegate
(“函数对象”),但它只在第一种情况下创建一个闭包,因为lambda不一定需要“捕获”引用环境在所有情况下。
答案 1 :(得分:69)
里德的回答是正确的;我只想添加一些额外的细节:
lambda表达式和匿名方法都有闭包语义;也就是说,它们“捕获”它们的外部变量并延长这些变量的生命周期。
匿名函数是我们在使用 lambda表达式或匿名方法时使用的术语。是的,这很令人困惑。抱歉。这是我们能想到的最好的。
可以作为对象处理的函数只是一个委托。使lambda成为闭包的原因在于它捕获了它的外部变量。
转换为表达式树的lambda表达式也有闭包语义,有趣的是。正确地实施这个是一个痛苦的问题,我告诉你!
“this”被认为是“外部变量”,用于创建闭包,即使“this”不是变量。
答案 2 :(得分:12)
这是“封闭”而不是“clojure。”
这不是闭包。闭包基本上是函数的表示以及函数消耗的任何非局部变量。
从这个意义上讲,lambdas不是闭包,但如果它们关闭任何变量,它们确实会导致编译器生成闭包。
如果在包含一个关闭某些变量的lambda的程序集上使用ILDASM,您将在该程序集中看到一个编译器生成的类,该类重新表示该函数以及已关闭的那些变量。 是关闭。
当你说
时被视为对象的函数
通常只是“函数对象”(在C#中我们说“委托”)并且在函数式编程中很常见。
答案 3 :(得分:8)
是。闭包通常从外部范围捕获变量。 Lambdas可以做到这一点。但是,如果你的lambda没有捕获任何东西,它就不是一个闭包。