Ruby: 4種類の同等性比較: equal?/eql?/==/===(翻訳)

概要

原著者の許諾を得て翻訳・公開いたします。

Ruby: 4種類の同等性比較: equal?/eql?/==/===(翻訳)

Rubyのさらなる特異な性質として、同等性の比較があります。さほど複雑ではありませんが、名前に注意しましょう。

同等性比較の4つの概念

1. equal?: オブジェクトの同一性比較

これはわかりやすい概念です。x.object_id == y.object_idのように、2つのオブジェクトが完全に同一であるべきだと考えられます。

2. ==(ダブルイコール): 「同等性」の同等性

これは大抵の場合注意が必要です。2つのオブジェクトは同じとして扱われるべきです。そのクラスで<=>ロケット比較演算子がサポートされている場合、==が同じ2つの値についてtrueを返すことが期待されているならば<=>0を返します。

3. eql?: ハッシュキーの同等性

これは通常==と同じ動作です。eql?は普通オーバーライドされた==メソッドのエイリアスです。

eql?の最も重要な効果は、ハッシュキーを区別するときに発揮されます。ドキュメントには以下のように書かれています。

hash値が同一かつ2つのオブジェクトが互いにeql?の場合、2つのオブジェクトは同じハッシュキーを参照する。

次は現実的な例です。

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

# すなわち以下の2つは異なるキーとして扱われる
{1: "Idiosyncratic", 1.0 "Hash"}

つまりeql?==より少しばかり厳格です。2つのオブジェクトが同一クラスのインスタンス同士でない場合はfalseを返すためです。典型的な実装は以下のようになります。

def eql?(other)
  instance_of?(other.class) && self == other
end

4. ===(トリプルイコール): 自在な同等性

これはcase文で暗黙に使われます。通常は==と同じ動作ですが、何らかの種類のクラスであるなどの関係もあることを意味します。

コアクラスにおける同等性比較の実装

クラス eql? == ===
Object 同一かどうか(equal?と同様) eql?と同じ ==と同じ
Symbol
Numeric 同じ型、同じ値 ロケット演算子が0を返す形で値が同じ
String 同じ長さ、同じ内容 他方がStringならeql?、それ以外はother.to_str===self
Regexp 他方がRegexpなら同じパターン/同じオプション/同じエンコーディング eql?と同じ 他方がStringならselfと一致
Array 同じ長さかつ全要素が.eql?で互いに等しい 同じ長さかつ全要素が.eql?で互いに等しい: 他方は.to_ary暗黙に変換される
Hash 同じ長さかつ全要素が==で互いに等しい(順序は問わず) eql?と同じ
Module other.is_a?(self)
Class other.is_a?(self)

表の-は未定義またはObjectの実装が使われることを表します。

サブクラスでのベストプラクティス

  • 2つのオブジェクトが同じであると考えられる場合にtrueを返すよう、意味のある==を定義しましょう
  • eql?は、2つのオブジェクトが同一クラスのインスタンスである場合にのみ、==と同じ値を返すようにしましょう
  • equal?は再定義してはなりません
  • ===の実装には創意を盛り込みましょう(ただし納得できるレベルで: 他の人はこれを用いて関係性を便利にチェックできると期待するものです)

参考

  • equalizer — オブジェクトのインスタンス変数を元に==eql?を自動で定義するgemです

関連記事

Rubyの===演算子についてまとめてみた

Ruby inside: トリプルイコール === の黒魔術(翻訳)

デザインも頼めるシステム開発会社をお探しならBPS株式会社までどうぞ 開発エンジニア積極採用中です! Ruby on Rails の開発なら実績豊富なBPS

この記事の著者

hachi8833

Twitter: @hachi8833、GitHub: @hachi8833 コボラー、ITコンサル、ローカライズ業界、Rails開発を経てTechRachoの編集・記事作成を担当。 これまでにRuby on Rails チュートリアル第2版の半分ほど、Railsガイドの初期翻訳ではほぼすべてを翻訳。その後も折に触れてそれぞれ一部を翻訳。 かと思うと、正規表現の粋を尽くした日本語エラーチェックサービス enno.jpを運営。 実は最近Go言語が好き。 仕事に関係ないすっとこブログ「あけてくれ」は2000年頃から多少の中断をはさんで継続、現在はnote.muに移転。

hachi8833の書いた記事

週刊Railsウォッチ

インフラ

ActiveSupport探訪シリーズ