【发布时间】:2013-04-24 20:21:24
【问题描述】:
y = lambda { z }
z = 9
y.call
=> NameError: undefined local variable or method `z' for main:Object
y = lambda { z }
y.call
=> 9
我认为拥有一个块的想法是推迟块内代码的执行。你能解释一下吗?
【问题讨论】:
y = lambda { z }
z = 9
y.call
=> NameError: undefined local variable or method `z' for main:Object
y = lambda { z }
y.call
=> 9
我认为拥有一个块的想法是推迟块内代码的执行。你能解释一下吗?
【问题讨论】:
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 复制和粘贴代码并在调用它时对其进行评估不同。 evaling 字符串会这样做:
y = "z"
z = 9
eval(y)
# => 9
同样,闭包的想法是它捕获代码和环境。
【讨论】:
在第一行中,当创建块时,根本没有z 可以被块“捕获”。当你第二次写y = lambda { z }时,有一个z。
该块拍摄周围变量的一种快照。在这种情况下,第一次不存在名为 z 的变量。
【讨论】:
当你定义一个 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
那么一切都会好起来的。
【讨论】:
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。
【讨论】: