E.g. order by name vs order by height.
Each implementation will be relevant to a separate struct using Person.
Can I do that in the same compilation unit without the following error ?
error[E0119]: conflicting implementations of trait `std::cmp::Ord` for type Person
I wouldn't recommend doing this, as it makes it unclear what alice < bob means. It's fine just to compare the fields: alice.height < bob.height. Functions that use orderings typically take a by_key variant, e.g. people.sort_by_key(|p| p.height);.
What you can do is write several newtypes for Person, each with its own implementation of PartialOrd and Ord e.g.
struct NamePerson(Person);
// impl PartialOrd and Ord for NamePerson so `PartialOrd` and `Ord` order by name
struct HeightPerson(Person);
// impl PartialOrd and Ord for HeightPerson so `PartialOrd` and `Ord` order by height
Thanks for your suggestions.
I am working with heaps.
So I would like to have one heap ordered by name and one heap ordered by height.
It seems to me overkill / immoral to define two different types of Persons to this end.
In Java, the problem is solved by passing a custom comparator to the PriorityQueue.
If OP is using std::collections::BinaryHeap then there's no opportunity to pass in a custom comparator; I think newtypes are the blessed solution here.
Once you get the grasp of using wrapper types, you can generalize over any kind of comparison function, if you so wish (granted, this would ideally be provided by some library, although as youc an see it can be written by hand):
use lib::BinaryHeapWithCustomComparator;
#[derive(Clone, Debug)]
struct Person {
id: u32,
name: String,
height: u32,
}
fn main ()
{
let p1 = Person {
id: 1,
name: "p1".into(),
height: 42,
};
let p2 = Person {
id: 2,
name: "p2".into(),
height: 27,
};
let p3 = Person {
id: 3,
name: "p3".into(),
height: 0,
};
let mut heap = BinaryHeapWithCustomComparator::new(
|p1: &'_ Person, p2: &'_ Person| {
::core::cmp::Ord::cmp(&p1.height, &p2.height)
}
);
heap.push(p1.clone());
heap.push(p2.clone());
heap.push(p3.clone());
eprintln!("Tallest person: {:?}", heap.peek().unwrap());
let mut heap = BinaryHeapWithCustomComparator::<Person, _>::new(|p1, p2| {
::core::cmp::Ord::cmp(&p1.name, &p2.name)
});
heap.push(p1);
heap.push(p2);
heap.push(p3);
eprintln!("By name, the last person is: {:?}", heap.peek().unwrap());
}