Rubyのオブジェクトの等値性
Rubyにおいて、オブジェクトの等値性を確かめる方法がいくつもあり、それぞれの方法で性質が違うので、ややこしくならないようにまとめておきます。
主な方法は以下の4種
equal?
==
eql?
===
equal?メソッド
2つの値が同一のオブジェクトを参照しているかをテストします。
a = "hoge" b = c = "hoge" a.equal? b # => false b.equal? c # => true
aとbは同じ文字列 hoge ですが、オブジェクトが異なるので違うもの扱い。
a.object_id == b.object_id # => false
という調べ方もあります。
== 演算子
Objectクラスでは、equal?
メソッドと同じ意味ですが、他のクラスでは再定義されてequal?
と異なる挙動をする場合が多い。
例えば、Stringクラスでは文字列が同じかどうか、Integerクラスでは整数値が同じかどうかをテストします。インスタンスが違っていても問題ありません。
a = "hoge" b = "hoge" x = 100 y = 100 a == b # => true x == y # => true
eql?メソッド
Objectクラスではequal?
の別名として定義されています。
eql?
を再定義するクラスでは、型変換をしない厳格な==
としてこのメソッドを使うことが多いようです。
1 == 1.0 # => true 1.eql? 1.0 # => false
=== 演算子
いわゆるcase等値で、その名の通りRubyのcase文でのマッチングに使われます。
多くの場合、==
と同じ挙動をしますが、Range
、RegExp
、Class
あたりのクラスが特別な挙動をします。
(1..10) === 5 /[0-9]+/ === "123456789" String === "string"
Range
クラスでは、右辺の値が範囲内にあるかどうかをテストします。
RegExp
クラスでは、右辺の文字列が正規表現にマッチするかどうかをテストします。
Class
クラスでは、右辺のオブジェクトがそのクラスのインスタンスになっているかをテストします。
まとめ
どの比較方法もクラスによって挙動が同じだったり異なったりしていてややこしいです。
オブジェクトの等値性をチェックするときは、いくつか性質の違う方法があることを念頭に置いておくべきだと思いました。