1
y = lambda { z }
z = 9

y.call
=> NameError: undefined local variable or method `z' for main:Object

y = lambda { z }
y.call
=> 9

我认为拥有一个块的想法是推迟块内代码的执行。你能解释一下吗?

4

4 回答 4

2

When you define a lambda, it gets a closure, consisting of references to all the variables in scope at the time of definition. The lambda always has access to the current value of each variable it has "closed over", but newly defined variables aren't added to the closure retroactively. So when you do this:

x = 5
y = lambda { x + z }
z = 7

the lambda y has access to the value of x, but not z, because only x was in existence at the time you defined the lambda. But if you do this:

x = 5
z = 0
y = lambda { x + z }

z = 7
y.call
# => 12

then all will be well.

于 2013-04-24T20:31:31.330 回答
2

lambda创建所谓的词法闭包,这意味着它捕获对封闭环境的引用,并且可以使用创建闭包时范围内的变量。

y = lambda { z } # Woops! There's no variable named `z`!

是否创建一个以创建闭包z 命名的变量并不重要;闭包的想法是它捕获了那个特定时刻的环境。

从理论上讲,您可能希望在创建该 lambda 时出现错误,因为可以对其进行分析并确定将取消引用尚未定义的变量。然而,Ruby 不是这样工作的。只有在评估代码时,您才会因尝试访问未定义的变量而出错。

当您在几行之后创建第二个闭包时,该闭包确实捕获了一个z存在的环境:

y = lambda { z } # This closure is broken and can't be fixed
z = 9
y = lambda { z } # This is a new closure, and `z` is accessible within it

我认为拥有一个块的想法是推迟块内代码的执行。

有点,但它与简单地从 lambda 复制和粘贴代码并在调用它时对其进行评估不同。 eval一个字符串会这样做:

y = "z"
z = 9
eval(y)
# => 9

同样,闭包的想法是它同时捕获代码环境。

于 2013-04-24T20:41:00.380 回答
2

在第一行中,当创建块时,还没有任何东西z可以被块“捕获”。当你写y = lambda { z }第二次时,有一个z.

该块拍摄周围变量的一种快照。z在这种情况下,第一次没有出现命名变量。

于 2013-04-24T20:24:21.043 回答
1

undefined local variable or method 'z' for main:Object在未创建局部变量时出现。assignment仅由操作创建的局部变量。

您的第一个y = lambda { z }无法z按照z此定义后的定义进行绑定lambda

以下作品:

y = lambda { z }
y.call
=> 9

正如您z = 9在第二个 lambda 定义之前定义的那样。

于 2013-04-24T20:23:02.070 回答