Custom struct as key to hashmap

I have a struct called “ArgSpec” which - simplified - contains:

pub struct ArgSpec {
  opt: Option<char>,
  lopt: Option<String>,
}

I want to be able to use this as a key in a HashMap. I know exactly how I want the ordering to behave. But I’m not quite sure how to implement it. When I build the code it complains that std::cmp::Eq isn’t implemented for ArgSpec. This is expected, but my question is how to implement it. I tried the following (in the same module):

impl PartialEq for ArgSpec {
  fn eq(&self, other: &Self) -> bool {
    true
  }
}

But I get the same error.

I know I’m missing something very basic here, but what?

Try changing your code to:

#[derive(PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ArgSpec {
  opt: Option<char>,
  lopt: Option<String>,
}

This instructs the compiler to automatically generate impls for your struct for all the named traits.

2 Likes

This builds, but I’m going to admit I find it a little confusing that it does (since ArgSpec contains members which are Option<>). But looking beyond this snippet, ArgSpec will eventually contain other members which shouldn’t be used to key the data (only opt and lopt should do that). Am I correct in assuming this means I have to manually implement the traits?

For comparisons, None is less than Some, and the rest should be straightforward.

But yes, if you want a partial comparison, you will need to implement the traits manually. When you do, take care that they are all consistent, per the notes on PartialEq and Hash:

One way you could “cheat” is to group your comparison items into one sub-struct and derive on that. Then the manual impls on the full struct can just forward to that one member. Someday there may be a way to derive “delegate” impls like this.

3 Likes

Ah, yes, of course. I’ll simply add a dedicated key sub-struct. It’s obvious now that you’ve said it. Cheers!

2 Likes