“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专家称它们为“块”,因为它们是由{
… }
或do
… end
语法创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。 块和封闭之间的区别也分别与上述相同。