Files
100-exercises-to-learn-rust/book/src/06_ticket_management/16_btreemap.md
Luca Palmieri 99591a715e Formatter (#51)
Enforce consistent formatting use `dprint`
2024-05-24 17:00:03 +02:00

2.6 KiB
Raw Blame History

Ordering

By moving from a Vec to a HashMap we have improved the performance of our ticket management system, and simplified our code in the process.
Its not all roses, though. When iterating over a Vec-backed store, we could be sure that the tickets would be returned in the order they were added.
Thats not the case with a HashMap: you can iterate over the tickets, but the order is random.

We can recover a consistent ordering by switching from a HashMap to a BTreeMap.

BTreeMap

A BTreeMap guarantees that entries are sorted by their keys.
This is useful when you need to iterate over the entries in a specific order, or if you need to perform range queries (e.g. “give me all tickets with an id between 10 and 20”).

Just like HashMap, you wont find trait bounds on the definition of BTreeMap. But youll find trait bounds on its methods. Lets look at insert:

// `K` and `V` stand for the key and value types, respectively,
// just like in `HashMap`.
impl<K, V> BTreeMap<K, V> {
    pub fn insert(&mut self, key: K, value: V) -> Option<V>
    where
        K: Ord,
    {
        // implementation
    }
}

Hash is no longer required. Instead, the key type must implement the Ord trait.

Ord

The Ord trait is used to compare values.
While PartialEq is used to compare for equality, Ord is used to compare for ordering.

Its defined in std::cmp:

pub trait Ord: Eq + PartialOrd {
    fn cmp(&self, other: &Self) -> Ordering;
}

The cmp method returns an Ordering enum, which can be one of Less, Equal, or Greater.
Ord requires that two other traits are implemented: Eq and PartialOrd.

PartialOrd

PartialOrd is a weaker version of Ord, just like PartialEq is a weaker version of Eq. You can see why by looking at its definition:

pub trait PartialOrd: PartialEq {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering>;
}

PartialOrd::partial_cmp returns an Option—it is not guaranteed that two values can be compared.
For example, f32 doesnt implement Ord because NaN values are not comparable, the same reason why f32 doesnt implement Eq.

Implementing Ord and PartialOrd

Both Ord and PartialOrd can be derived for your types:

// You need to add `Eq` and `PartialEq` too,
// since `Ord` requires them.
#[derive(Eq, PartialEq, Ord, PartialOrd)]
struct TicketId(u64);

If you choose (or need) to implement them manually, be careful:

  • Ord and PartialOrd must be consistent with Eq and PartialEq.
  • Ord and PartialOrd must be consistent with each other.