42

我发现很多人可以互换使用关闭。这些人大部分都无法解释他们在说什么。一些Java程序员(甚至是来自非常昂贵的咨询公司的人)都会将匿名内部类作为“块”和“闭包”进行讨论 - 但我知道这是不正确的。 (你不能从他们在定义该方法的范围内通过可变的变量...)“封闭”与“块”之间的区别究竟是什么?

我在寻找:

  • 精确,计算机科学定义的方框
  • 封闭
  • 澄清的精确,计算机科学定义在两者之间的差异

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

+0

我不确定他们是否有准确的定义,例如Apple添加到gcc的闭包被称为“块” – cobbal 2009-11-29 02:13:19

+0

如果您在谈论[]的 - 他们从Smalltalk进入Objective-C,他们是编译成一个名为BlockClosure的混淆事例。 – daf 2009-11-29 02:35:23

+2

他不是在谈论Objective-C,而是在谈论苹果对C的扩展。在OSX 10.6 Snow Leopard中,Appel引入了一个名为Grand Central Dispatch的新并发库。这是一个基于任务的库,有点类似于微软的Task Parallel Library。 GCD的基本思想是将一段代码交给库,然后库决定何时和在哪个内核上执行。通常情况下,你可以用函数指针来做到这一点,但苹果公司认为这太难看了,他们用基本上是lambda表达式的C语言来扩展C,他们称之为块。 – 2010-01-23 12:08:01

回答

27

虽然只是一块可以由语句和声明,但没有别的组成码,闭合是一个真正的第一类对象,其具有块作为其值实数变量。

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

如果你有一个闭包,通常你可以将它作为参数传递给函数,进行currify和decurrify,主要称它为!

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

当然倒闭更强大,他们是变量,可以用来定义对象的自定义行为(而通常你不得不使用接口编程或其他OOP方法)。

您可以将关闭视为包含该功能自身内部功能的函数。

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

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

t是块(for语句体)内定义,将持续仅仅是块内。

+0

块也标记“对象范围”的开始。 – jldupont 2009-11-28 12:28:51

+0

你是对的,忘记提及..刚刚更新 – Jack 2009-11-28 12:30:46

+0

for循环的例子不会泛泛而谈,因为“闭包”与Javascript一起使用的语言比其他语言更多,并且循环块不会封装它们的变量除了* only *和函数声明。我怀疑你的例子是Java?请明确说明。 – 2013-06-05 22:56:33

16

块是语法上的东西 - 语句的逻辑单元(更多与范围关闭)。

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

的封闭涉及anoymous函数或类 - 匿名(功能)对象,一段代码绑定到的环境(其变量)。

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

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

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

注意,只是红宝石中块和关闭都同样对待,因为什么Ruby调用块是一个关闭:

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

each - 方法传递一个闭合功能(拍摄参数x)在Ruby中被称为

+0

......然后就是和Smalltalk混淆了。 Ruby程序员称之为块,Smalltalk称之为“BlockClosure”! – daf 2009-11-30 17:13:05

+0

实际上,在你的Ruby例子中,block是* not *闭包,因为它没有关闭任何东西。更有趣的是'a = 7; (1..10).each do | x | p a << x end'或类似的东西。 – 2010-01-23 12:00:35

1

这些日子在Ruby中最常用的术语是,尽管之前的结构出现在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。当你轻松创建一个匿名函数时,事实证明它们对于各种事物都很有用。

但是请注意,后f回报,那么g回报,我们从f返回它(如x)举行的块,然后从g(如t)。现在我们再次调用该块。再次请注意,g()已返回。但是这个块指的是一个不存在的函数实例(和范围)中的局部变量?!它获得了新的价值y?!

因此,闭包是一个类似于函数的对象,它在其词法范围上关闭。它们实现起来相当具有挑战性,因为它们会破坏对函数调用实例中局部变量非常有用的堆叠式处理模型。


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

+0

这个答案中的代码片段是为什么我不使用Ruby的完美例证。 – 2016-01-14 14:35:51

2

响亮,长胡子的人有这样说的封锁和块:

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

在一个点上,他说,一个闭包是可以作为参数传递给方法传递一个块。

+0

我只是发现闭包的概念比块更加普遍和明确。如果已经有真正的关闭,我没有看到区块的需要。 – 2014-04-12 20:22:18

+0

感谢您的链接! – 2015-01-16 22:15:31

+0

@WeiQiu正如我在上面的回答中或多或少地说过的那样,'return'的行为包含了块关闭的大部分基本原理,作为与函数关闭分离的实体。 – 2015-06-17 17:17:25

4

这里有很多混乱,因为有多个定义的术语,以及多个不同的事物,因为它们通常被发现在一起而被混合。

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

其次,我们有可调用代码作为值类型。在函数式语言中,这些是函数值 - 有时称为“funs”,“匿名函数”(因为该函数可以在值中找到,而不是指定给它的名称;你不需要名称来调用它们),或者“ lambdas“(来自运算符,用于在教会的Lambda微积分中创建它们)。它们可能被称为“封闭”,但它们不是自动关闭;为了限定它们,它们必须封装(“关闭”)围绕它们创建的词法范围 - 也就是说,定义在函数范围之外但在定义范围内的变量在调用函数时仍然可用,甚至如果调用点是在被引用的变量超出范围并且其存储被回收之后。

尽管如此,您可以拥有不是全部函数的可调用代码值。 Smalltalk将这些“块关闭”称为“块关闭”,而Ruby将其称为“特效”。但大多数Rubyists只是称它们为“块”,因为它们是由{ ... }do ... end语法创建的具体化版本。是什么使它们与lambda函数(或“函数闭包”)不同?它们不引入新的子程序级别。 如果块闭包主体中的代码调用return,它将从块外部函数/方法返回,而不仅仅是块本身。

该行为对保留R.D. Tennent标记为“对应原则”至关重要,该原则声明您应该能够用包含该代码的内联函数替换任何代码并立即调用。与此

x = 2; 

:例如,在JavaScript中,你可以更换该

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

我的例子不是很有趣,但有能力做这种转变,而不会影响的行为程序在功能重构中起着关键作用。问题是,只要你嵌入return陈述,原则不再成立。

这就是为什么Ruby同时具有特效和lambda--这是常常引起新手混淆的原因。 procs和lambdas都是类Proc的对象,但它们的行为不同,如上所述:一个return仅从lambda的主体返回,但它从围绕proc的方法返回。 (另外,虽然与我在此绘制的区别无关,但如果使用错误数量的参数调用lambdas检查arity并发出抱怨,您可以通过在对象上调用.lambda?来确定该类型。)

当前为Javascript只有功能关闭,虽然在桌面上有一个建议来引入块关闭语言。

0

这是一个整数

诠释workDaysInAWeek = 5

这是一个整数变量并且它可以被设置为不同的整数。 (如果情况不允许你修改的值,它可以被称为不变

尽管上述数字的关注,关闭关注算法。 区块的区别也分别与上述等同。