Rubyの同一性・同値性判定について軽い備忘録。
あらゆるオブジェクトは値と一意的なIDをもつ。
オブジェクトIDは .object_idメソッドで確かめられる。
例えば、
a = 2.0
b = 2
c = "2".to_i
d = 2.0.to_i
e = 2.to_f
puts a.object_id #=> 23370708
puts b.object_id #=> 5
puts c.object_id #=> 5
puts d.object_id #=> 5
puts e.object_id #=> 23370708
2つのオブジェクトを比較するとき、「.equal?」、「.eql?」、「==」、「===」などを使う。aとbを比較すると
puts a.equal? b #=> false
puts a.eql? b #=> false
puts a == b #=> true
puts a ===b #=> true
==,===については同値性を、equal?はID同一性を確かめている。
eql?はクラスによって振る舞いが変わる。Stringに対しては同値性(なので「==」と同じ)、Numericに対しては同一性(なので「equal?」と同じ)の判定を行う。
別の例として
s = "puyo"
t = "pu"
u = "yo"
v = t+u
w = "pu"+"yo"
puts s #=> puyo
puts v #=> puyo
puts w #=> puyo
IDと同一性・同値性を確かめると
puts s.object_id #=> 23433564
puts v.object_id #=> 23367516
puts w.object_id #=> 23367480
puts s.equal? v #=> false
puts s.equal? w #=> false
puts s.eql? v #=> true
puts s.eql? w #=> true
puts s == v #=> true wとの比較も同様
puts s === v #=> true wとの比較も同様
関連してIDについて触れておくと、NumericとStringとで決まり方が異なる
a = 2
b = 2
c = 1 + 1
puts a.object_id #=> 5
puts b.object_id #=> 5
puts c.object_id #=> 5
α = "pu"
β = "yo"
x = α+β
puts x.object_id #=> 23532144
γ = "pu"
δ = "yo"
y = γ+δ
puts y.object_id #=> 23532084
z = "puyo"
puts z.object_id #=> 23532060
z = "puyo"
puts z.object_id #=> 23532036
Numericは値に対してIDが決まるが、Stringについては変数に値を格納する毎にIDが変わる
最後にハッシュについて。
ハッシュの値参照を行う際、ハッシュオブジェクトの内部では.eql?メソッドでキーIDを比較している。そのため次のような振る舞いをする。
h = {"i"+"d" => "value"}
puts h["i"+"d"] #=> value
puts h["id"] #=> value
k = {2.0 => :valuable}
puts k[2.0] #=> valuable
puts k[2] #=> nil