【问题标题】:Variable in else condition assumed nil value [duplicate]其他条件下的变量假定为零值[重复]
【发布时间】:2014-02-06 11:31:24
【问题描述】:

这是我在 ruby​​ 1.9.3 中发现的一些奇怪的东西。

代码如下:

>> r = true
>> if r
>>   a  = "hello"
>> else
>>   b = "hello"
>> end

现在a 的值为“hello”:

>> a
=> "hello"

奇怪的是b 的值是 nil

>> b
=> nil

由于b 在场景中不存在,因此应该未声明。

为什么?

【问题讨论】:

    标签: ruby local-variables


    【解决方案1】:

    即使从未到达进行赋值的分支,变量声明也会生效。

    【讨论】:

    • @Patritosh:我刚刚运行了你的代码,然后运行了puts b.object_id # => 70364348734500。如您所见,对象b 已创建并赋予值nil
    • @CarySwoveland:这很奇怪。您使用的是什么 Ruby 实现?它不是规范要求的,但在所有甚至远程流行的 Ruby 实现(MRI、YARV、Rubinius、JRuby、IronRuby、MRuby、Ruby.NET、XRuby、MagLev、MacRuby、Cardinal、Topaz、BlueRuby、Ruby GoLightly、tinyrb)上, nilobject_id4
    • @Jörg,确实很奇怪!应该是b.object_id # => 8。 (我正在使用 MRI 2.0.0)。那么我是如何得到 70364348734500 的呢?这是一个 IRB 陷阱。我之前使用变量b 来测试其他东西,并在运行询问者的代码和puts b.object_id 后忽略了检查它的值。为什么我没有注意到有什么不对劲?对此没有任何解释。 object_id of nil 在 2.0 中是 changed to 8
    • 啊,是的,我忘记了 YARV 2.0 中 flonums 的额外标记位。 (顺便说一句:对象 ID 是特定 Ruby 实现的私有内部实现细节。不能保证它们在不同的实现中是相同的。甚至不能保证它们在同一程序的多次运行中是相同的。所以,当你说 nil 的 ID 在 2.0 中更改了,您的具体意思是它在 YARV 2.0 中更改,而不是在 Ruby 2.0 中。Ruby 2.0 没有为nil 或任何其他对象对object_id 的值做出任何保证。)
    • @Jörg,你是一个坚持不懈的人(你的职业中一个非常理想的特质,imo——我说“你的”,因为对我来说编码只是一种爱好)。并感谢您的澄清。
    【解决方案2】:

    原因在Ruby documentation 中有解释,它适用于任何版本的 Ruby,而不仅仅是 1.9:

    当解析器遇到 分配,不是在分配发生时

    这意味着如果解析器在代码中看到一个赋值,它会创建局部变量,即使该赋值永远不会真正发生。在这种情况下,变量引用的值是nil

    if true
      a = 0
    else
      b = 0
    end
    
    p local_variables
    # => [:a, :b]
    
    p a
    # => 0
    
    p b
    # => nil
    

    【讨论】:

      【解决方案3】:

      当解析器遇到 分配,而不是分配发生时:

      => foo
      # NameError: undefined local variable or method `foo' for main:Object
      => if false
      =>   foo = "bar" # does not assign to foo
      => end
      => nil
      => foo
      => nil
      

      【讨论】:

      猜你喜欢
      • 2016-04-20
      • 2016-05-29
      • 1970-01-01
      • 2015-09-13
      • 2015-03-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多