プログラミング学習メモ

RubyとRuby on Rails等

同値性と同一性

Rubyでは等しいか比較をする時
基本的にレシーバとなるオブジェクトのクラスにオーバーライド(再定義)された

Object#==  
Object#===
Object#equal?

を用います。

それぞれ等しいならtrue、異なるならfalseとなる点は同じですが、判断基準が異なります。

==

==は同値性を判断しています。

a = 'abc'
b = 'abc'
a == b #=>true

同値性とは文字の通り、値が等しいとtrueとなります。
上記は値は等しいですが、別のオブジェクトです

a.object_id #=>70337627390140
b.object_id #=>70337627471920

また、Integerクラス(整数)やFloatクラス(浮動小数点数)等の数値、シンボルは値が等しいと、同じオブジェクトとなります。

int = 1
int2 = 1
int.object_id #=> 3
int2.object_id #=> 3

Object#equal?

Object#equal?は同一性を判断しています。

==の例の文字列も同一性はありません

a.equal? b #=>false

同一のオブジェクトを参照している時のみtrueとなります。

c = a
a.equal? c #=>true

rubyにおいて複製などをする際、オブジェクトの要素はコピーせずにそのまま参照することがあります。

ary = %w[1 2 3] #=>["1", "2", "3"]
#cloneはレシーバのオブジェクトのコピーを出力
ary2 = ary.clone
ary[0].equal? ary2[0] #=> true
ary3 = %w[a b]       #=> ["a", "b"]
#Array#*は要素を引数の数だけ繰り返す
re = ary3 * 2        #=> ["a", "b", "a", "b"]
re[0].equal? re[2]  #=>true
ary3[0].equal? re[0] #=>true

同じオブジェクトを破壊的メソッドを使用した時、参照している全てに影響してしまいます。

#上の続き
ary[0]       #=>"1"
#succは次の数字や文字を出力。succ!は破壊的メソッド
ary[0].succ! #=>"2"
ary          #=>["2", "2", "3"]
ary2         #=>["2", "2", "3"]

===

===は基本的に同値性で判断しますが、case文のバックで用いられるため、クラスによって==とは異なる内容の再定義がされている場合があります。

等式は可換(左右を入れ替えても結果が同じ)ですが、上記の理由で===では非可換となる場合があります。

/[a-z]+/ === 'string'  #=>true
 'string' === /[a-z]+/ #=>false

これはRegexpクラス(正規表現)ではRegexp#===として正規表現にマッチすればtrueとなる再定義されている。しかしStringクラスはString#==と同じ再定義しているため可換性がなくなっています。

参考

Ruby 逆引きハンドブック