Manually implementing PartialOrd
for a type that derives Ord
can lead to inconsistencies, as the implementations of these
traits must agree for sorting and other comparisons. According to the trait contract, the following must hold for any type implementing
Ord
:
k1.cmp(&k2) == k1.partial_cmp(&k2).unwrap()
Using a default-generated Ord
implementation with an explicitly defined PartialOrd
is a risky practice that may cause
unexpected behavior.
Code examples
Noncompliant code example
#[derive(Ord, PartialEq, Eq)]
struct Foo;
impl PartialOrd for Foo {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
None // Noncompliant: Manually implemented PartialOrd when Ord is derived.
}
}
Compliant solution
#[derive(PartialEq, Eq)]
struct Foo;
impl PartialOrd for Foo {
fn partial_cmp(&self, other: &Foo) -> Option<Ordering> {
Some(self.cmp(other)) // Compliant: Manual implementation is consistent with Ord.
}
}
impl Ord for Foo {
fn cmp(&self, other: &Foo) -> Ordering {
// Implementation here
}
}
Or, if a custom ordering is not needed:
#[derive(Ord, PartialOrd, PartialEq, Eq)]
struct Foo; // Compliant: Both Ord and PartialOrd are derived.