En Rust, les traits PartialEq et Eq proviennent de la philosophie de la sécurité des types — toutes les opérations fondamentales pour les collections (HashMap, HashSet) reposent sur une définition stricte de l'égalité. Les traits définissent si des objets de deux types peuvent être comparés à l'aide de == et obligent le type à réaliser une "égalité complète" (Eq) ou "partielle" (PartialEq).
Une mauvaise implémentation de PartialEq/Eq conduit à un fonctionnement incorrect des collections, où les propriétés mathématiques de base sont violées : la comparaison avec soi-même, la symétrie, la transitivité. De plus, un Eq incorrect peut entraîner la "perte" d'objets dans les collections ou la génération de doublons inattendus.
PartialEq est implémenté pour les types pour lesquels la comparaison n'est pas possible pour toutes les valeurs (par exemple, f32, où NaN != NaN). Eq est réservé uniquement aux relations "strictes" (totales). Les types personnalisés doivent implémenter la comparaison en stricte accordance avec ces contrats.
Exemple de code :
#[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); // vrai
Caractéristiques clés :
Pourquoi pour le type f32 la bibliothèque standard n’implémente-t-elle que PartialEq, mais pas Eq ?
Parce qu'en vertu de la norme IEEE-754, NaN != NaN, c'est-à-dire que la propriété x == x pour tous les x n'est pas respectée, et c'est une propriété nécessaire pour Eq.
Est-il obligatoire d'implémenter Eq explicitement si PartialEq est implémenté manuellement ?
Oui, si le type supporte l'égalité complète (x == x est toujours vrai), il est nécessaire d'implémenter manuellement Eq, sinon certaines structures ne compileront pas avec votre type.
Un utilisateur peut-il implémenter PartialEq de manière "non symétrique" (x == y, mais y != x) ?
Techniquement oui, mais cela entraîne un fonctionnement incorrect des collections et est considéré comme un bug.
** Cas négatif
L'utilisateur a implémenté PartialEq pour un type comparant uniquement un champ, les autres étant ignorés. En conséquence, HashSet "perd" les doublons.
Avantages:
Inconvénients:
** Cas positif
Utilise #[derive(PartialEq, Eq)] ou implémente sa propre version de la comparaison, tenant compte de toute la logique métier, garantissant les propriétés requises.
Avantages :
Inconvénients :