与this question中一样,当未定义的局部变量在其自己的赋值中使用时,它将被计算为nil
。
x = x # => nil
但是当局部变量的名称与现有方法名称冲突时,它会更棘手。为什么下面的最后一个示例会返回nil
?
{}.instance_eval{a = keys} # => []
{}.instance_eval{keys = self.keys} # => []
{}.instance_eval{keys = keys} # => nil
答案 0 :(得分:12)
在Ruby中,因为可以在没有显式接收器且没有括号的情况下调用方法,所以在局部变量引用和无接收器无参数方法调用之间存在语法歧义:
foo
可以 表示“foo
上没有参数的调用方法self
”或“取消引用局部变量foo
”。
如果范围内存在局部变量foo
,则始终解释为局部变量解除引用,从不作为方法调用。
那么,局部变量“在范围内”意味着什么?这是语法在解析时, not 在运行时语义上确定的。这是非常重要的!局部变量在解析时定义:如果解析器看到对局部变量的赋值,则局部变量在此范围内。但是,它只在运行时中进行了初始化,没有对代码进行编译时评估:
if false
foo = 42 # from this point on, the local variable foo is in scope
end
foo # evaluates to nil, since it is declared but not initialized
为什么局部变量对“影子”方法有意义而不是方法呢?好吧,如果方法确实影响了局部变量,那么就不再有一种方法可以取消引用那些局部变量。但是,如果局部变量为阴影方法,那么仍然有一种方法可以调用这些方法:记住,模糊性只存在于无接收无参数方法调用中,如果添加显式接收器或显式参数列表,您仍然可以调用该方法:
def bar; 'Hello from method' end; public :bar
bar # => 'Hello from method'
bar = 'You will never see this' if false
bar # => nil
bar = 'Hello from local variable'
bar # => 'Hello from local variable'
bar() # => 'Hello from method'
self.bar # => 'Hello from method'
答案 1 :(得分:1)
简短的回答是,因为Matz如此定义。这种行为是我不喜欢Ruby的极少数事情之一。它甚至变得更好:
a = b if a
=> nil
a
=> nil
变量a
被初始化为nil,即使理论上a = b语句也不应该被执行。
答案 2 :(得分:-3)
我认为在你的情况下,这是因为它是预期的:P
1.9.3-p194 :001 > {}.instance_eval{a=1}
=> 1
1.9.3-p194 :002 > {}.instance_eval{a}
NameError: undefined local variable or method `a' for {}:Hash
from (irb):2:in `block in irb_binding'
from (irb):2:in `instance_eval'
from (irb):2
from /Users/rafael/.rvm/rubies/ruby-1.9.3-p194/bin/irb:16:in `<main>'
Instance eval在实例级别评估代码,因此您声明的每个哈希都是不同的。如果你想返回密钥,那么
1.9.3-p194 :003 > {}.instance_eval{keys = self.keys
1.9.3-p194 :004?> keys = keys}
=> []