Impl Eq for struct with f64 field I want ignore

I have

pub struct PointLastValue {
    #[serde(rename = "ref")]
    pub ref_info: String,
    pub namespace: String,
    pub timestamp: u64,
    pub value: f64,
}

and I want todo

let mut hashmap: HashMap<String, PointLastValue> = HashMap::new();
for point in values {
    hashmap.insert(point.ref_info.clone(), point);
}

However, I can't impl Eq as there is a f64 field. I understand this but how do I handle it these days.

I am not interested in the value field for Eq at all and would like to ignore it.

Ie

Hash would be

impl Hash for PointLastValue {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.ref_info.hash(state);
        self.namespace.hash(state);
    }
}

But I still have to deal with Eq ?

Nothing is stopping you from implementing Eq yourself, but you can also use ordered-float or similar crates that wrap floats with total ordering.

1 Like

Alternatively, there are crates like derivative that allow you to customize the automatic implementation.

#[derive(Derivative, Serialize, Deserialize, Debug)]
#[derivative(Eq, PartialEq, Hash)]
pub struct PointLastValue {
    #[serde(rename = "ref")]
    pub ref_info: String,
    pub namespace: String,
    #[derivative(PartialEq = "ignore", Hash = "ignore")]
    pub timestamp: u64,
    #[derivative(PartialEq = "ignore", Hash = "ignore")]
    pub value: f64,
}

Just make sure you use the same fields for Eq and Hash, otherwise you could get logic errors.

2 Likes

That's a nice crate. Would love that in the std lib.

An easy way to manually implement Eq, Ord, Hash etc traits is to delegate to a tuple impl:

  impl PartialEq for PointLastValue {
      fn eq(&self, other: &Self) -> bool {
          let Self { ref_info, namespace, timestamp, value: _ } = other;
          (&self.ref_info, &self.namespace,  &self.timestamp)
              .eq(&(ref_info, namespace, timestamp))
      }
  }

This is particularly useful with Ord where doing it (more) manually is not entirely trivial. You can write a helper method that returns the tuple to make sure the trait impls are consistent with each other. Note the use of value: _ rather than .. so the compiler compilains if you add a field and forget to update the tuple.

4 Likes