我发现很多人把「闭包(closure)」和「块(block)」这两个词混用,其中大部分人无法解释自己在谈论什么。
一些Java程序员(甚至是来自非常昂贵的咨询公司的程序员)称匿名内部类为「块(block)」和「闭包(closure)」,但我知道这不是真的。(你不能从定义它们的方法作用域中传递可变变量...)
我正在寻找:
- 一个精确、计算机科学定义块(block)
- 一个精确、计算机科学定义闭包(closure)
- 阐述二者之间差异的内容。
请提供链接、文章或书籍参考资料。
我发现很多人把「闭包(closure)」和「块(block)」这两个词混用,其中大部分人无法解释自己在谈论什么。
一些Java程序员(甚至是来自非常昂贵的咨询公司的程序员)称匿名内部类为「块(block)」和「闭包(closure)」,但我知道这不是真的。(你不能从定义它们的方法作用域中传递可变变量...)
我正在寻找:
请提供链接、文章或书籍参考资料。
块(block)只是由语句和声明组成的代码片段,而闭包(closure)是一个真正的一等对象,一个包含块作为值的变量。
主要区别在于块仅仅是将指令组合在一起(例如while语句的主体),而闭包是一个包含可执行代码的变量。
如果你拥有一个闭包,通常可以将它作为参数传递给函数,进行柯里化和去柯里化,最重要的是可以调用它!
Closure c = { println 'Hello!' }
/* now you have an object that contains code */
c.call()
for (int i = 0; i < 10; ++i)
{
int t = i*2;
printf("%d\r\n", t);
}
t
定义在块内(for
语句的主体)中,仅在该块内有效。
一个代码块是语法上的一个概念 - 一组语句的逻辑单元(与闭包不同,更多地与作用域相关)。
if (Condition) {
// Block here
}
else {
// Another block
}
闭包与匿名函数或类相关 - 它是一个绑定到环境中的变量(及其变量)的代码片段的匿名(函数)对象。
def foo() {
var x = 0
return () => { x += 1; return x }
}
这里的 foo
返回了一个闭包!本地变量 x
通过该闭包保留,即使在 foo
终止后也是如此,并且可以通过调用返回的匿名函数来递增。
val counter = foo()
print counter() // Returns 2
print counter() // Return 3
请注意,这仅适用于Ruby,其中块(block)和闭包(closure)被视为类似,因为Ruby所谓的块是闭包:
(1..10).each do |x|
p x
end
在Ruby中,each
方法接受一个闭包函数(带有参数x),这个闭包函数在Ruby中被称为块。
a = 7; (1..10).each do |x| p a << x end
或类似的东西。 - Jörg W Mittagfunction makeClosure() {
var x = "Remember me!";
return function() {
return "x='" + x + "'";
}
}
// console.log(x);
// The above is an error; x is undefined
var f = makeClosure();
console.log(f());
// The above outputs a string that includes x as it existed when f was created.
x
只在函数 makeClosure
的主体内部定义;在该定义之外,它不存在。调用完 makeClosure
后,其中声明的 x
应该被删除。从大多数代码的角度来看,确实如此。但是,由 makeClosure
返回的函数是在存在 x
的情况下声明的,因此当您稍后调用它时,它仍然可以访问它。这使它成为一个真正的闭包。{
...}
或 do
...end
语法创建的具体版本。使它们与 lambda(或“函数闭包”)不同的是,它们不会引入新的调用级别。如果块闭包中的主体代码调用 return
,则它会从该块闭包所在的外部函数/方法返回,而不仅仅是块本身。x=2
console.log(x)
(function(){x = 2;})();
console.log(x)
那个例子并不是很有趣,但是能够进行这种转换而不影响程序行为的能力在函数重构中起着关键作用。但是使用Lambda表达式后,一旦嵌入了return
语句,原则就不再适用:
function foo1() {
if (1) {
return;
}
console.log("foo1: This should never run.")
}
foo1()
function foo2() {
if (1) {
(function() { return; })();
}
console.log("foo2: This should never run.")
}
foo2()
return
只从匿名函数返回,而不从foo2
返回,所以会执行console.log
。这破坏了对应原则。Proc
类对象,但它们的行为不同,如上所述:在lambda中,return
只从函数体返回,但在proc中,它会从包含proc的方法返回。def test
p = proc do return 1 end
l = lambda do return 1 end
r = l[]
puts "Called l, got #{r}, still here."
r = p[]
puts "Called p, got #{r}, still here?"
end
test
方法永远不会执行第二个puts
,因为调用p
会立即导致test
返回(并带有返回值1)。如果Javascript有块级闭包,你可以做同样的事情,但它没有(尽管有提议添加它们)。return
的行为构成了块闭包作为与函数闭包分开实体的大部分基础。 - Mark Reed这些术语在如今的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有各种不同的闭包函数对象,这只是其中之一。
5
这是一个 整数。
Int workDaysInAWeek = 5
这是一个整数变量,可以设置为另一个整数。(如果情况阻止您修改该值,则可以称为常量。)
而上述内容涉及数字,块和闭包涉及算法。分别区分块和闭包的区别也相当于上述问题。
BlockClosure
的实例。 - Dafydd Rees