在Ruby中,为什么与nil(“Date.new == nil”)的相等性返回nil?

时间:2010-02-08 23:26:08

标签: ruby date equality

今天写一些rspec时,我遇到了一些意外行为,将Date(和Time)实例与nil进行比较。这是使用原始ruby(没有Rails或其他库)的示例:

user@MacBook-Work ~ $ ruby -v
ruby 1.8.7 (2008-08-11 patchlevel 72) [universal-darwin10.0]
user@MacBook-Work ~ $ irb
>> 1 == nil
=> false
>> "string" == nil
=> false
>> :sym == nil
=> false
>> false == nil
=> false
>> [] == nil
=> false
>> {} == nil
=> false
>> Proc.new {} == nil
=> false

到目前为止,这么好,对吧?

>> Date.new == nil
=> nil
>> Time.new == nil
=> nil

Date确实实现了自己的===,这很好用:

>> Date.new === nil
=> false

有没有解释为什么会发生这种情况或者为什么会出现这种情况? ==似乎是从Comparable实现的。==,但是关于它的文档没有任何迹象表明它会返回nil。对此有何设计决定?

更新!这不是1.9.2中的情况:

$ irb
ruby-1.9.2-p136 :001 > require 'date'
 => true 
ruby-1.9.2-p136 :002 > Date.new == nil
 => false 
ruby-1.9.2-p136 :003 > Time.new == nil
 => false 

4 个答案:

答案 0 :(得分:12)

我查看了源代码,这是我发现的内容:

Comparable定义的比较运算符全部使用函数rb_cmpint<=>。当其中一个操作数为nil时,rb_cmpint会引发异常。

因此,如果rhs与lhs不具有可比性,则Comparable的运算符会引发异常。即5 < 2为false,但5 < "la"引发异常。他们这样做是为了区分<因为rhs较小而不是真的情况和由于rhs不具有可比性而不适用的情况。或者换句话说:当x < y为假时,表示x >= y为真。因此,如果不是这种情况,则会引发异常。

==引发异常会很糟糕,因为==通常不会(也不应该)要求其操作数具有可比性。但是==使用与其他操作数相同的方法,这会引发异常。所以整个函数只包含在rb_rescue中。如果抛出异常,则返回nil

请注意,这仅适用于ruby 1.8。这已在1.9中修复,现在==永远不会返回nil(当然,如果您定义自己的==,则除外)。

答案 1 :(得分:7)

如果您依赖于此代码,您可以随时使用.nil?任何Ruby对象响应的方法。

>> Date.new.nil?
=> false

答案 2 :(得分:4)

Date类包含Comparable#==方法,但该方法调用接收方的<=>方法。在这种情况下,Date#<=>,期望另一个Date对象。收到nil后,它会返回nil。这种行为当然似乎不一致,我不知道背后的原因。

答案 3 :(得分:0)

这是因为您无法比较未定义的内容。这是可取的,因为如果你的操作数中至少有一个未被定义,那么你就无法得出任何关于结果的结论,这与断言真理不同。

许多语言都将nil和false视为同样的,这是纯粹为了方便起见。这肯定不是数学上正确的。