NameError:undefined – 在Ruby 2.1.2中更改了局部变量的解析规则吗?

我得到NameError: undefined local variable or method使用ruby 2.1.2的NameError: undefined local variable or method

正如在这个问题中观察到的,表达式如:

 bar if bar = true 

引发未定义的局部变量错误(假设事先未定义bar ),因为解析器在分配之前会读取bar 。 而且我相信这个表达与以前没有区别:

 bar if bar = false 

两者之间的区别在于主体是否被评估,但是如果遇到未定义的局部变量,则在评估条件之前立即引发错误并不重要。

但是当我在Ruby 2.1.2上运行第二个代码时,它不会引发错误。 它之前是这样吗? 如果是这样,那么解析讨论的内容是什么? 如果没有,Ruby规范是否已更改? 有没有提到这个? 它在1.8.7,1.9.3等中做了什么?

是的,它在ruby 2.1.2中有所改变

1.8.7甚至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 `
' 2.1.2 :002 > bar if bar = false (irb):2: warning: found = in conditional, should be == => nil

这是在我的Ubuntu 14上

关于是否定义了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

添加@JörgWMittag 答案 。

另一个常见的令人困惑的情况是在使用修饰符if

 pa if a = 0.zero? # => NameError: undefined local variable or method `a' 

您不会打印“true”而是收到NameError,“未定义的局部变量或方法”a“”。 由于ruby解析了if的左边,并且尚未看到对它的赋值,因此假定你想调用一个方法。 然后,Ruby会将赋值视为a,并假设您正在引用本地方法。

混淆来自表达式out-of-order执行。 首先分配局部变量,然后尝试调用不存在的方法。

根据以上解释 –

 bar if bar = false 

简单地返回nil ,因为表达式已被评估false ,因此不会执行与if修饰符关联的代码的主体。 默认情况下,当没有显式默认值时 ,Ruby中的任何都返回nil

Interesting Posts