Rust에서 PartialEq와 Eq는 타입 안전성이라는 철학에서 유래되었습니다. 컬렉션의 모든 기본 연산(HashMap, HashSet)은 동등성에 대한 엄격한 정의를 기반으로 합니다. 이 트레이트는 두 유형의 객체가 ==를 사용하여 비교될 수 있는지 및 유형이 "완전한" 동등성(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
주요 특징:
왜 f32에 대해 표준 라이브러리는 PartialEq만 구현하고 Eq는 구현하지 않았나요?
IEEE-754에 따라 NaN != NaN이므로, 모든 x에 대해 x == x라는 속성이 충족되지 않으며, 이는 Eq에 필수적인 속성입니다.
PartialEq를 수동으로 구현한 경우, Eq를 명시적으로 구현해야 하나요?
예, 유형이 완전한 동등성을 지원하는 경우(x == x가 항상 true라면), Eq를 수동으로 구현해야 하며, 그렇지 않으면 일부 구조체가 귀하의 유형과 함께 컴파일되지 않을 것입니다.
사용자가 PartialEq를 "비대칭적으로" 구현할 수 있나요? (x == y이지만 y != x)?
기술적으로 가능합니다. 그러나 이것은 컬렉션의 잘못된 작동을 초래하며 버그로 간주됩니다.
** 부정적인 사례
사용자가 하나의 필드만 비교하여 PartialEq를 구현했으며, 나머지 필드는 무시됩니다. 결과적으로 HashSet이 중복을 "잃어버립니다".
장점:
단점:
** 긍정적인 사례
#[derive(PartialEq, Eq)]를 사용하거나 모든 비즈니스 로직을 고려하여 비교의 자체 버전을 구현하여 요구되는 속성을 보장합니다.
장점:
단점: