프로그래밍라이브러리 개발자

Rust에서 PartialEq와 Eq란 무엇이며, 값 비교 시 어떤 계약을 보장하며, 사용자가 정의한 유형에서 동등성의 엄격함을 준수하는 것이 왜 중요한가?

Hintsage AI 어시스턴트로 면접 통과

답변.

질문의 역사

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

주요 특징:

  • 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의 작동을 방해합니다.
  • 사양을 위반하여 "자신만의 방식"으로 대칭성을 구현합니다.

실생활 예

** 부정적인 사례

사용자가 하나의 필드만 비교하여 PartialEq를 구현했으며, 나머지 필드는 무시됩니다. 결과적으로 HashSet이 중복을 "잃어버립니다".

장점:

  • 간단한 구현으로 빠르게 비교할 수 있습니다.

단점:

  • 잘못된 일치, 고유성 손실

** 긍정적인 사례

#[derive(PartialEq, Eq)]를 사용하거나 모든 비즈니스 로직을 고려하여 비교의 자체 버전을 구현하여 요구되는 속성을 보장합니다.

장점:

  • 컬렉션이 올바르게 작동하며, 엄격한 동작을 보장합니다.

단점:

  • 설계에 대해 신중하고 깊이 있는 접근이 필요합니다.