Block第一次无法识别变量

时间:2013-04-24 20:21:24

标签: ruby lambda block

y = lambda { z }
z = 9

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

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

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

4 个答案:

答案 0 :(得分:2)

在第一行中,当创建块时,根本就没有z可以被捕获"在街区之前。当您第二次写y = lambda { z }时,会有z

该块采用周围变量的一种快照。在这种情况下,第一次没有名为z的变量。

答案 1 :(得分:2)

当你定义一个lambda时,它会得到一个闭包,它包含对定义时范围中所有变量的引用。 lambda总是可以访问它已“关闭”的每个变量的当前值,但是新定义的变量不会追溯地添加到闭包中。所以当你这样做时:

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

lambda y可以访问x的值,但不能访问z,因为在定义lambda时只存在x。但如果你这样做:

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

z = 7
y.call
# => 12
然后一切都会好的。

答案 2 :(得分:2)

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

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

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

答案 3 :(得分:1)

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

您的第一个y = lambda { z }无法绑定z,因为此z定义后定义了lambda

以下作品:

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

在第二个lambda定义之前定义z = 9