6

我正在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 等中做了什么?

4

3 回答 3

5

关于是否bar定义没有区别。在这两种情况下,bar在正文中都是未定义的。但是,在后一种情况下,从不评估身体,因此没关系。您永远不会解析 name bar,因此在名称解析期间永远不会出错。

局部变量是在解析赋值时定义的。它们在执行分配时被初始化

将变量统一化是非常好的。在这种情况下,它只会评估为nil

if false
  bar = 42
end

bar
# => nil

然而,如果变量是undefined,那么 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将在正文中定义。但事实并非如此,因为首先解析了主体,因此在看到赋值之前,我不知道这是一个方法还是一个变量节点被插入到语法树中。

但是,如果从不解释该节点,即条件为假,则不会发生任何不好的事情。

于 2014-08-14T11:34:27.303 回答
1

是的,它在 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 上

于 2014-08-14T11:40:46.930 回答
1

我的答案基于Ruby 2.1.2

添加@Jörg W Mittag answer

另一个常见的令人困惑的情况是使用修饰符时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

只需return nil,因为表达式已被评估false,与修饰符关联的代码主体if将不会被执行。Ruby 中nil的任何块都会返回,默认情况下,当没有明确的默认值时。

于 2014-08-14T11:36:38.253 回答