我得到NameError: undefined local variable or method
与ruby 2.1.2
从这个问题中可以看出,像
这样的表达式:bar if bar = true
引发一个未定义的局部变量错误(前提是bar
没有预先定义),因为bar
在赋值之前被解析器读取。我相信在过去,这和这个表达式是没有区别的:
bar if bar = false
两者的区别在于是否对主体进行求值,但如果遇到未定义的局部变量,在计算条件之前立即引发错误,则这无关紧要。
但是当我在Ruby 2.1.2上运行第二段代码时,它没有引发错误。以前是这样的吗?如果是这样,那么解析讨论是关于什么的?如果没有,Ruby规范改变了吗?有没有提到这一点?在1.8.7、1.9.3等版本中,它做了什么?
是否定义bar
无差异。在这两种情况下,bar
在主体中都是未定义的。然而,在后一种情况下,函数体永远不会被求值,因此这无关紧要。您永远不会解析名称bar
,因此在名称解析期间您永远不会得到错误。
局部变量是定义的。当赋值被执行时,它们被初始化。
变量被初始化是完全可以的。在这种情况下,它的值就是nil
:
if false
bar = 42
end
bar
# => nil
但是,如果变量未定义,那么Ruby不知道裸字是局部变量还是无接收方无参数消息发送:
foo
# NameError: undefined local variable or method `foo'
# ^^^^^^^^^
# Ruby doesn't know whether it's a variable or a message send
与
foo()
# NoMethodError: undefined method `foo'
# ^^^^^^^^^^^^^
self.foo
# NoMethodError: undefined method `foo'
# ^^^^^^^^^^^^^
现在都在一起了:
foo()
# NoMethodError: undefined method `foo'
self.foo
# NoMethodError: undefined method `foo'
foo
# NameError: undefined local variable or method `foo'
if false
foo = 42
end
foo
# => nil
foo = :fortytwo
foo
# => :fortytwo
在这种特殊情况下的问题是表达式解析的顺序(以及变量定义的顺序)与表达式执行的顺序不匹配。赋值首先在执行,这将使您假设bar
将在体中定义。但它不是,因为主体是首先解析的,因此我不知道这是一个方法还是一个变量节点在赋值之前被插入到语法树。
但是,如果该节点从不被解释,即条件为假,则不会发生任何不良事件
在ruby 2.1.2中有改变
在1.8.7
, 1.9.3
, 2.0.0
甚至2.1.1
中,我得到2个警告,没有错误:
2.0.0-p247 :007 > bar if bar = false
(irb):7: warning: found = in conditional, should be ==
=> nil
2.0.0-p247 :008 > bar if bar = true
(irb):8: warning: found = in conditional, should be ==
=> true
而在2.1.2
版本中,你提到我得到2个警告和1个NameError
错误。
2.1.2 :001 > bar if bar = true
(irb):1: warning: found = in conditional, should be ==
NameError: undefined local variable or method `bar' for main:Object
from (irb):1
from /home/durrantm/.rvm/rubies/ruby-2.1.2/bin/irb:11:in `<main>'
2.1.2 :002 > bar if bar = false
(irb):2: warning: found = in conditional, should be ==
=> nil
这是我的Ubuntu 14
我的答案是基于Ruby 2.1.2。
添加@Jörg W Mittag答案
另一个常见的混淆情况是使用修饰符if
:
p a if a = 0.zero? # => NameError: undefined local variable or method `a'
不是打印"true",而是收到一个NameError,"未定义的局部变量或方法' a '"。由于ruby首先解析if的左侧,并且还没有看到对a的赋值,因此它假设您希望调用一个方法。然后Ruby看到对a的赋值,并认为你引用了一个局部方法。
混淆来自于表达式的out-of-order
执行。首先给局部变量赋值,然后尝试调用一个不存在的方法。
基于上面的解释-
bar if bar = false
简单地返回nil
,因为表达式已经计算为false,与if
修饰符相关的代码体不会被执行。nil
是由Ruby中的任何块返回的,默认情况下,当没有显式的默认值时