“closures”和“块”之间究竟有什么区别?

我发现很多人可以互换地使用闭包 。 这些人大多不能解释他们在说什么。

一些Java程序员(甚至是来自非常昂贵的咨询公司的人)都会将匿名内部类作为“块”和“闭包”进行讨论 – 但我知道这不是事实。 (你不能在它们被定义的方法范围内传递可变variables…)

我在找:

  • 一个精确的,计算机科学的块定义
  • 一个精确的计算机科学的封闭定义
  • 澄清两者的区别

我真的很希望看到这些链接,文章或书籍参考

虽然只是一段可以由语句和声明组成的代码,但没有别的, 闭包是一个真正的第一类对象,它是一个真正的variables,它有一个块作为它的值。

主要区别在于块简单地将指令组合在一起(例如while语句的主体),而闭包是包含一些可以执行的代码的variables。

如果你有一个闭包,通常你可以把它作为一个parameter passing给函数,进行currify和decurrify,主要是这样的!

 Closure c = { println 'Hello!' } /* now you have an object that contains code */ c.call() 

当然,闭包function更强大,它们是variables,可以用来定义对象的自定义行为(而通常你必须在编程中使用接口或其他OOP方法)。

你可以把闭包想象成一个函数,它包含了这个函数自身内部的function。

块是有用的,因为它们允许variables的范围。 通常当你在一个范围内定义一个variables的时候,你可以毫无问题的重写外部定义,并且在块的执行期间新的定义将会存在。

 for (int i = 0; i < 10; ++i) { int t = i*2; printf("%d\r\n", t); } 

t是在块( for语句的主体)内定义的,并且会在该块内部持续。

块是语法的东西 – 语句的逻辑单元(与范围相比更closures )。

 if (Condition) { // Block here } else { // Another block } 

闭包与匿名函数或类有关 – 一个匿名(函数)对象,是一个绑定到一个环境(与其variables)的代码片段。

 def foo() { var x = 0 return () => { x += 1; return x } } 

这里foo返回一个闭包! 即使在foo终止之后,局部variablesx仍然通过闭包持续存在,并且可以通过调用返回的匿名函数来增加。

 val counter = foo() print counter() // Returns 2 print counter() // Return 3 

请注意,Ruby中的block和closure被相似的处理,因为Ruby调用block 是一个闭包:

 (1..10).each do |x| px end 

在这里, each方法都传递一个闭包函数(取一个参数x),在Ruby中被称为

这里有很多困惑,因为有多个定义的术语,而多个不同的东西因为它们通常被一起发现而被合并。

首先,我们有“块”。 这只是一个代码的词汇块,例如一个循环的主体。 如果语言实际上具有块范围,则可以定义只存在于该块代码中的variables。

其次,我们有可调用的代码作为一个值types。 在函数式语言中,这些是函数值 – 有时被称为“funs”,“匿名函数”(因为函数在值中被find,而不是被赋值的名字;你不需要名字来调用它们),或者“ lambdas“(来自运算符,用于在教会的Lambda微积分中创build它们)。 他们可能被称为“closures”,但不是自动closures; 为了限定,它们必须封装(“closures”)围绕它们的创build的词法范围 – 也就是说,定义在函数范围之外但在其定义范围内的variables在函数被调用时仍然可用,甚至如果调用点是在被引用的variables本来会超出范围并且其存储被回收的情况下。

尽pipe如此,您可以拥有不是全部函数的可调用代码值。 Smalltalk将这些“块closures”称为“块closures”,而Ruby则称之为“特效”。 但是大多数Ruby专家称它们为“块”,因为它们是由{}doend语法创build的指定版本。 什么使他们与lambda(或“函数闭包”)不同的是,他们没有引入新的子程序级别。 如果块闭包的主体中的代码调用return ,它将从外部函数/方法返回块闭包,而不仅仅是块本身。

这种行为对于保留RD Tennent标记为“对应原则”至关重要,该对应原则声明您应该能够用包含该代码的内联函数replace任何代码并立即调用。 例如,在Javascript中,你可以取代这个:

  x = 2; 

有了这个:

  (function(){x = 2;})(); 

我的例子不是很有趣,但是在不影响程序行为的情况下进行这种转换的能力在function重构中起着关键的作用。 问题是,只要你有embeddedreturn语句,原则不再成立。

这就是为什么Ruby同时拥有特效和lambdaexpression式 – 这是常常造成新手混淆的原因。 Proc和lambdas都是类Proc对象,但是它们的行为不同,如上所示: return只是从lambda的主体返回,但是从围绕proc的方法返回。 (另外,虽然与我在此绘制的区别无关,但如果使用错误数量的参数调用lambdas检查arity并抱怨,可以通过在对象上调用.lambda?来判断哪种types。

Javascript目前只有函数closures,尽pipe在表格中有一个提议将闭包引入语言。

大声的,胡须的人有这样的说:closures和块:

http://martinfowler.com/bliki/Closure.html

有一次,他说闭包是一个可以作为parameter passing给方法的块。

你现在使用的术语是Ruby中最常用的术语,尽pipe之前的结构出现在Algol,Smalltalk和Scheme中。 如果有的话,我会引用Ruby标准。

我不确定我能否回答你确切的问题,但我可以说明。 我很抱歉,如果你已经知道这个…

 def f &x yield x end def g y = "block" t = f { p "I'm a #{y}" } y = "closure" t end t = g t.call 

和…

 $ ruby exam.rb "I'm a block" "I'm a closure" $ 

所以一个块是一个匿名的函数式的代码序列附加到方法调用。 它遍布Ruby API。 当你简单地创build一个匿名函数时,事实certificate它们对于各种事情都是有用的。

但是请注意,在f返回之后, g返回,我们继续从f (如x ),然后从g (如t )返回块。 现在我们再次打电话给该块。 再次请注意, g()已经返回。 但块是指一个函数实例(和范围)中不再存在的局部variables?! 它获得了新的价值?

所以闭包是一个类似于函数的对象,它的词法范围是封闭的。 它们实现起来相当具有挑战性,因为它们会破坏对函数调用实例中的局部variables非常有用的“一栈一堆”模式。


1. Ruby具有各种types的闭包函数对象; 这只是其中之一。

这是一个整数

诠释workDaysInAWeek = 5

这是一个整数variables ,它可能被设置为一个不同的整数 。 (如果情况阻止你修改这个值,它可能被称为常量 。)

而以上关注的数字, closures关注algorithm。 封闭之间的区别也分别与上述相同。