这个问题具体涉及Ruby 1.9.3:
p defined?(a)
p binding.eval "defined?(a)"
b = lambda { |x| x }
p b.binding.eval "defined?(a)" # This prints "local-variable"
p defined?(a) # This prints nil!
a = 2
p defined?(a)
p b.binding.eval "defined?(a)"
令我困惑的是第四行。我不确定为什么打印“本地变量”而不是nil。这似乎意味着lambda在某种程度上“看得更远”。 (我认为作为运营商的defined?
与此有关。)
此外,尽管绑定表明已定义,但尝试使用它如下:
p b.binding.eval "a"
在之前第6行的赋值会导致NameError。
编辑: 我在
上测试了这个我在所有情况下都有相同的行为。
答案 0 :(得分:2)
只是在解析时调用defined?
,并且由于尚未存在变量a
,它会按预期返回nil
。但是,当您eval
调用defined?
时,它会延迟到运行时。但是defined?
仍然是词法范围的,并且由于整个文件已经被解析和编译,变量a
确实存在,因为它是在分析时创建的,现在已经完成了。
我们可以用简化的例子来说明这一点:
defined? a #=> nil
eval 'defined? a' #=> "local-variable"
a = 2
defined? a #=> "local-variable"
但是如果我们根本没有定义a
:
defined? a #=> nil
eval 'defined? a' #=> nil
正如您所看到的,它与binding
没有任何关系,而只是与eval
推迟评估defined?
直到整个文件之后已被解析。
答案 1 :(得分:0)
实际上,第六行是神秘的源头。即使代码未执行,Ruby也会在条件语句中创建对象。如果指定了变量,则隐式声明它。 This blog post has a quick explanation
我发现这有点令人惊讶。至于你的代码,在一个新的IRB会话中,你应该看到'nil'作为第四行的输出,但如果你多次运行代码,你的变量已经存在(以Nil对象的形式)而你我会得到一个局部变量存在的令人困惑的消息。 YMMV。
答案 2 :(得分:0)
这是Ruby源解析器的一个特性。如果在Ruby源代码中确实存在变量赋值,那么即使在程序执行期间从未调用过,它也会被初始化为nil(因此它被定义)。
第6行的赋值是局部变量 a (a = 2
)。无论是在第3行之后定义,因为它甚至在执行源之前被ruby解析器初始化为nil。由于lambda没有引入新的范围,它知道一个一个变量,所以你得到了“本地变量”结果(a == nil)。
有关详细信息,请参阅此answer。
在irb中运行或传递给ruby解释器之间的不同行为与上一段直接相关。 irb逐行计算表达式(REPL),ruby在执行之前解析整个源。