やりたいことがやりたい。

情報技術で学んだことや漫画の話を中心に、好きなことを色々書いていきます。

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文でのマッチングに使われます。

多くの場合、==と同じ挙動をしますが、RangeRegExpClassあたりのクラスが特別な挙動をします。

(1..10) === 5
/[0-9]+/ === "123456789"
String === "string"

Rangeクラスでは、右辺の値が範囲内にあるかどうかをテストします。

RegExpクラスでは、右辺の文字列が正規表現にマッチするかどうかをテストします。

Classクラスでは、右辺のオブジェクトがそのクラスのインスタンスになっているかをテストします。

まとめ

どの比較方法もクラスによって挙動が同じだったり異なったりしていてややこしいです。

オブジェクトの等値性をチェックするときは、いくつか性質の違う方法があることを念頭に置いておくべきだと思いました。