19

为什么下面的代码不会抛出错误?

if false
  x = 0
end

x  #=> nil

而以下确实会引发错误:

y  # NameError: undefined local variable or method `y' for main:Object

unless&case语句也会发生同样的事情。

4

3 回答 3

30

这是因为 Ruby 解析器的工作方式。变量由解析器定义,它逐行遍历代码,而不管它是否会实际执行。

一旦解析器看到,它将在当前范围内x =定义局部变量x(带有 value )。nil由于if////不创建新的范围,unless在代码块之外定义和可用case。并且由于内部块从未被评估为条件为假,因此未分配给(因此是)。forwhilexxnil

这是一个类似的例子:

defined?(x) and x = 0
x  #=> nil

请注意,这是对所发生情况的高级概述,不一定是解析器的工作方式。

于 2012-09-27T06:08:19.113 回答
4

这与 Ruby 范围规则的一个怪癖有关。

在 ruby​​ 中,x单独出现的未修饰变量可能是局部变量,也可能是方法调用——语法无法判断是哪一个。在解析局部变量引用时,由解析器来解决。规则很简单:如果已在本地范围内看到对同名变量的赋值,则引用是局部变量,并且引用绑定到该局部变量。否则,它是一个方法调用,它会在运行时被这样查找。

Ruby 中的局部变量引用被优化为数组查找(每个局部变量都被分配一个“槽”,解析器生成的绑定局部变量引用被转换为槽引用)。数组用 all 初始化nil

/* initialize local variables */
for (i=0; i < local_size; i++) {
    *sp++ = Qnil;
}

因此,如果您通过绑定的局部引用引用尚未分配的局部变量(仅当在同一局部范围内的引用上方存在跳过的分配时才会发生这种情况),您会得到nil.

于 2012-09-27T06:09:51.920 回答
1

我认为您的问题很有趣,所以我尝试查找并发现: 我不了解 ruby​​ 本地范围

正确的答案似乎是 Jorg。

让我们看看当您尝试访问未初始化的变量时会发生什么:

NameError: undefined local variable or method `UNDECLAREDVAR' for main:Object

异常指出无法评估变量或方法。它不抛出相同异常的原因是因为未初始化的局部变量被设置为 nil。所以puts x没关系,因为解释器知道这x是变量但未初始化而不是方法。

于 2012-09-27T06:15:14.840 回答