17

今日いくつかの rspec を書いているときに、Date (および Time) インスタンスを nil と比較すると、予期しない動作に遭遇しました。これは、生のルビーを使用したサンプルです (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

4 に答える 4

12

ソースを確認したところ、次のことがわかりました。

Comparable で定義された比較演算子はすべて、この関数rb_cmpintを とともに使用し<=>ます。rb_cmpintオペランドの 1 つが nil の場合、例外が発生します。

そのため、rhs が lhs と比較できない場合、Comparable の演算子は例外を発生させます。つまり5 < 2、false ですが5 < "la"、例外が発生します。<これは、rhs が小さいために が真でない場合と、rhs が比較できないために真ではない場合を区別するために行われます。言い換えれば、x < yそれが true であることを意味する when is falsex >= yです。そのため、そうでない場合は、例外がスローされます。

====通常、オペランドが比較可能であることを必要としない (またすべきではない)ため、例外を発生させることは悪いことです。ただし==、他のオペランドと同じメソッドを使用するため、例外が発生します。したがって、関数全体が単純にラップされますrb_rescue。そしてnil、例外がスローされた場合に戻ります。

これは ruby​​ 1.8 にのみ適用されることに注意してください。これは 1.9 で修正され、現在==は返されませんnil(もちろん、独自に定義した場合を除きます==)。

于 2010-02-08T23:38:03.767 に答える
7

コードでこれに依存している場合は、いつでも .nil? Ruby オブジェクトが応答するメソッド。

>> Date.new.nil?
=> false
于 2010-02-09T01:18:18.423 に答える
4

Date クラスにはメソッドが含まれていますが、そのメソッドはレシーバーComparable#==のメソッドを呼び出します。<=>この場合Date#<=>は、別の Date オブジェクトが必要です。受け取るnilと返しますnil。この動作は確かに一貫性がないように見えますが、その背後にある理由はわかりません。

于 2010-02-08T23:34:20.890 に答える
0

定義されていないものを比較できないために発生します。オペランドの少なくとも 1 つが定義されていない場合、結果について結論を出すことができないため、これは望ましいことです。これは、真実を主張することとは異なります。

多くの言語は nil と false を同じように扱いますが、これは純粋に便宜上のものと思われます。それは確かに数学的に正しくありません。

于 2010-02-09T01:43:53.743 に答える