解释为局部变量会覆盖方法名称吗?

正如在这个问题中 ,当未定义的局部变量在其自己的赋值中使用时,它将被计算为nil

 x = x # => nil 

但是当局部变量的名称与现有方法名称冲突时,它更棘手。 为什么下面的最后一个例子返回nil

 {}.instance_eval{a = keys} # => [] {}.instance_eval{keys = self.keys} # => [] {}.instance_eval{keys = keys} # => nil 

在Ruby中,因为可以在没有显式接收器且没有括号的情况下调用方法,所以在局部变量引用和无接收器无参数方法调用之间存在语法歧义:

 foo 

可能意味着“在没有参数的情况下调用self方法foo ”或“取消引用局部变量foo ”。

如果范围中存在局部变量foo ,则始终将其解释为局部变量取消引用,而不是方法调用。

那么,局部变量“在范围内”意味着什么呢? 这是在语法分析时语法上确定的, 而不是在运行时语义上确定的。 这是非常重要的! 局部变量在解析时定义:如果解析器看到对局部变量的赋值,则局部变量在该点的范围内。 但是,它只在运行时 初始化 ,没有编译时间的代码评估:

 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' 

简短的回答是,因为Matz如此定义。 这种行为是我不喜欢Ruby的极少数事情之一。 它甚至变得更好:

 a = b if a => nil a => nil 

变量a初始化为nil,即使理论上a = b语句也不应该在任何情况下执行。

我认为在你的情况下,这是因为它是预期的: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 `
'

Instance eval在实例级别评估代码,因此您声明的每个哈希都是不同的。 如果你想返回键,这是有效的

 1.9.3-p194 :003 > {}.instance_eval{keys = self.keys 1.9.3-p194 :004?> keys = keys} => []