Programmingライブラリ開発者

RustにおけるPartialEqとEqとは何か、値を比較する際の契約は何であり、ユーザー定義タイプでの厳密な等価性を遵守することが重要な理由は何ですか?

Hintsage AIアシスタントで面接を突破

回答。

問題の歴史

Rustにおいて、PartialEqとEqトレイトは型安全性の哲学から生まれており、すべてのコレクション(HashMap、HashSet)にとって基本的な操作は厳密な等価性の定義に基づいています。これらのトレイトは、2つの型のオブジェクトが==によって比較できるかどうか、また型が「完全」な等価性(Eq)または「部分的」な等価性(PartialEq)を実装する義務があるかどうかを定義します。

問題

PartialEq/Eqの不適切な実装は、自己比較、対称性、推移性の基本的な数学的性質が損なわれ、コレクションの誤動作を引き起こします。また、不適切なEqは、オブジェクトがコレクション内で「失われる」または予期しない重複が発生する原因となる可能性があります。

解決策

PartialEqは、比較が可能でないすべての値に対して機能する型(例えば、f32、NaN != NaN)のために実装されます。Eqは「厳密な」(全体的な)関係のために設計されています。ユーザー定義の型は、これらの契約に厳密に従って比較を実装する必要があります。

コードの例:

#[derive(PartialEq, Eq)] struct Point { x: i32, y: i32, } let p1 = Point { x: 1, y: 2 }; let p2 = Point { x: 1, y: 2 }; assert!(p1 == p2); // true

主な特徴:

  • PartialEqは「部分的」な比較を許可します - 正確に比較できない値(例えば、NaN)が存在する可能性があります。
  • Eqは完全な関係を要求します:x == xは常にtrueでなければなりません; すべての関係の性質が遵守される必要があります。
  • これらのトレイトの適切な実装はコレクションおよび標準ライブラリの関数にとって非常に重要です。

誤解を招く質問。

なぜf32型には標準ライブラリがPartialEqのみを実装し、Eqを実装していないのですか?

IEEE-754により、NaN != NaNであるため、すべてのxに対してx == xの性質が遵守されないからであり、これはEqのために必要な性質です。

PartialEqが手動で実装されている場合、Eqを明示的に実装する必要がありますか?

はい、型が完全等価性(x == xが常にtrue)をサポートする場合、手動でEqも実装する必要があります。さもなくば、いくつかの構造体はあなたの型でコンパイルを拒否します。

ユーザーはPartialEqを「非対称」に実装できますか?(x == yだがy != x)

技術的には可能ですが、これはコレクションの誤動作を引き起こし、バグとみなされます。

典型的なエラーとアンチパターン

  • 比較に必要な性質を無視してPartialEqの実装に「欠陥」をもたらす。
  • 実装可能な型に対してEqを実装せず、HashMap/HashSetの動作を破壊する。
  • 仕様を違反して「自分のやり方」で対称性を実装する。

実生活の例

** ネガティブケース

ユーザーが1つのフィールドに基づいてのみ比較するPartialEqを実装し、残りを無視した結果、HashSetが重複を「失う」ことになります。

利点:

  • 簡単な実装で、迅速な比較が可能

欠点:

  • 偽の一致、一意性の喪失

** ポジティブケース

#[derive(PartialEq, Eq)]を使用するか、ビジネスロジック全体を考慮した独自の比較バージョンを実装し、必要な性質を保証します。

利点:

  • コレクションが正しく動作し、厳密な動作を実現

欠点:

  • 設計に対する注意深く考慮したアプローチが必要