【问题标题】:I don't understand ruby local scope我不明白红宝石本地范围
【发布时间】:2010-11-11 13:26:59
【问题描述】:

在这个例子中,

def foo(x)
  if(x > 5)
    bar = 100
  end
  puts bar
end

然后 foo(6) 输出:100 而 foo(3) 什么也不输出。

但是,如果我将定义更改为

def foo(x)
  if(x > 5)
    bar = 100
  end
  puts bob
end

我收到“未定义的局部变量或方法”错误。

所以我的问题是为什么我在调用 foo(3) 并且 bar 从未设置时没有收到此错误?

【问题讨论】:

    标签: ruby


    【解决方案1】:

    这里发生了几件事。首先,在if 块内声明的变量与在方法顶层声明的变量具有相同的局部范围,这就是barif 之外可用的原因。其次,您会收到该错误,因为bob 被直接引用。 Ruby 解释器从未见过它,也从未见过它初始化过。但是,它已经在 if 语句中看到了 bar 之前的初始化。因此,当它被禁止时,它就知道它存在。结合这两者,这就是你的答案。

    【讨论】:

    • 谢谢,是的,我明白 bob 错误在哪里,只是不确定为什么我没有收到 bar 错误。你知道我是否可以依赖这种行为,它是规范的一部分吗?例如,我可以在 if 语句之后检查 bar 是否为 nil,还是真的应该在 if 语句之前明确声明 bar = nil?
    • 是的,这是可靠的行为。声明 bar = nil 肯定会更明确。但我不知道大多数红宝石学家会这样做。如果您的方法保持较小,那么应该不难理解或查看 bar 的来源。
    【解决方案2】:

    您的第二个示例实际上是一个红鲱鱼:您得到异常的原因不是因为bob 未初始化,而是因为它不明确。分不清是变量还是方法。

    您的第一个示例有效,因为未初始化的局部变量(以及全局变量和实例变量)的计算结果为 nil。因此,puts bar 非常好:在一种情况下,bar 被初始化为100,其计算结果为100,在另一种情况下,它未初始化,因此计算结果为nilputs 在其参数上调用 to_s,该参数是为 nil 定义的(它只是返回空字符串),所以一切都很好。

    另见In Ruby, why after starting irb, foo.nil? says undefined error, and @foo.nil? gives “true”, and @@wah.nil? gives error again?

    【讨论】:

    • 我不了解 Ruby,但如果这是正确的,那么 Todd 接受的答案大概是不正确的。他暗示 bob 的问题不在于它为 nil,而在于它未初始化。其他答案表明您是正确的。
    • @Jörg:非常感谢,现在你让我明白了。我想知道马茨是不是太忙了,无法像你现在解释的那样清楚这一点。很好的答案!
    【解决方案3】:

    所以不要把它当作福音(因为它更多地基于观察而不是理解),但似乎 ruby​​ 解释器会将任何单词(前面没有印记)标记到等号的左侧作为当地人。你的例子很奇怪,这更离奇

    def foo
      bar = bar
      puts bar // nil, which gets coerced into ""
    end
    

    我不明白它为什么或如何工作,但你有它。

    【讨论】:

    • +1! JavaScript 的工作方式相同。它将所有声明移到顶部并将分配留在它们所在的位置。这可能有点令人困惑。
    • 分配的 LHS 上的所有内容都将初始化为零:>> if false ; test = whatever ; end ; test #=> nil。这也是x ||= 5 之类的工作方式,因为这意味着x = x || 5 将是x = nil || 5,以防x 之前没有定义。
    • @jwueller Ruby 并没有将所有作业移到顶部。 puts b; b = b; 导致 NameError: undefined local variable or method `b' for main:Object
    • @MichaelKohl 好吧,当 xx= 是方法时,x ||= 5 不一定等同于 x = x || 5。例如。 object.x ||= 5 (stackoverflow.com/a/27628662/1157054)。但在大多数情况下,您是正确的。
    【解决方案4】:

    foo(3) 不输出任何内容。它输出一个换行符。

    使用inspect 会给你更多提示:

    def foo(x)
      if(x > 5)
        bar = 100
      end
      puts bar.inspect
    end
    
    foo(3)
    

    打印出来

    nil
    

    bar 是一个成熟的变量,它的值恰好是 nil

    【讨论】:

      【解决方案5】:

      我不确定你在问什么。使用第二个定义运行foo(3) 总是会出错,因为从未定义过bob。该方法的参数不会改变这一点。

      【讨论】:

        猜你喜欢
        • 2017-04-01
        • 2011-02-04
        • 2018-02-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多