1. ホーム
  2. スクリプト・コラム
  3. ルビートピックス

Rubyの4つの比較関数(equal?, eql?, ==, ===)について解説します。

2022-02-01 09:50:35

Rubyにはequal?, eql?, ==, ===という4つの比較メソッドがあり、クラスによって挙動が大きく異なる。また、それらを使用する際に混乱しがちです。このブログでは、それぞれのメソッドについて、いくつかのコードを示して説明します。

== - クラスの意味で同等、各クラスは独自の実装を定義する必要があります。

ある特定のクラスで2つのオブジェクトが同一だと感じるかどうかは、ビジネスの論理的な表現を見て、すべてプログラマがメソッドの定義を上書きして、2つのオブジェクトが同一かどうかを判断する必要があるのです。

例えばStringクラスは、同じメモリ領域から出てきたかどうかを気にするのではなく、実際の文字列が同じかどうかを数えるためにここにあるのです。

>> a = "abc"
#=> "abc"

>> b = a + ""
#=> "abc"

? > a == b
#=> true

>> a.object_id
#=> 70255156346640

>> b.object_id
#=> 70255156340640



=== - case文の中で使用されたときに呼び出されるメソッド

このメソッドは通常、次のような大文字小文字の比較で呼び出されます。

case some_object
when /a regex/
 # The regex matches
when String
 # some_object is kind of String
when 2..4
 # some_object is in the range 2..4
when lambda {|x| some_crazy_custom_predicate }
 # the lambda returned true
end


は、以下と同等です。

if /a regex/ === some_object
 # The regex matches
elsif String === some_object
 # some_object is kind of object
elsif (2..4) === some_object
 # some_object is in the range 2..4
elsif lambda {|x| some_crazy_custom_predicate } === some_object
 # the lambda returned true
end


eql? - 通常のイコールの意味

2つのオブジェクトが同じ値を持つ場合に真を返します。一般に、サブクラスの == メソッドが再定義されると、eql?メソッドへのエイリアスが必要になります。もちろん、整数と分数を比較する2つのメソッドの戻り値が異なるような例外はあります。

1 == 1.0 #=> true
1.eql? 1.0 #=> false


eql?はHashでメンバの値を比較するために使用されます。

[1] pry(main)> hash = Hash.new
#=> {}
[2] pry(main)> hash[2] = "a"
#=> "a"
[3] pry(main)> hash[2.0] = "b"
#=> "b"
[4] pry(main)> hash[2]
#=> "a"
[5] pry(main)> hash[2.0]
#=> "b"
[6] pry(main)> hash[2.00] = "c"
#=> "c"
[7] pry(main)> hash[2.0]
#=> "c"


したがって、このメソッドをいつオーバーライドすべきかは、Hash比較の際にどのように動作させたいかによります。

イコール?- オブジェクトが同じメモリアドレスの場合

このメソッドはサブクラスでオーバーライドしないでください。
比較対象は、2つのオブジェクトがメモリ上で同じであり、かつ同じ object_id 値を持つかどうかである
Railsで時間的に同一なオブジェクト

q = User.first
 User Load (40.4ms) SELECT "users". * FROM "users" ORDER BY "users". "id" ASC LIMIT 1
#=> #<User id: 1, email: "[email protected]">

q2 = User.first
 User Load (0.4ms) SELECT "users". * FROM "users" ORDER BY "users". "id" ASC LIMIT 1
#=> #<User id: 1, email: "[email protected]">

q.equal? q2
#=> false



メモリーメソッド

  1. == ビジネスに必要なメソッドをオーバーライドする
  2. === caseステートメントをオーバーライドする際のパフォーマンス
  3. eql? メソッドのエイリアスで、Hashの比較を変更する必要がある場合はメソッドをオーバーライドします。
  4. イコール?変更なし