4

Using derive syntax, can I implement traits like Hash or PartialEq using specific fields, not all of them?

It could look like:

#[derive(Debug, Hash, Eq, PartialEq)]
struct MyStruct {
    id: i32,
    name: String,

    #[derive(hash_skip, eq_skip)] 
    aux_data1: f64,
    #[derive(hash_skip, eq_skip)]
    aux_data2: f64,
    #[derive(hash_skip, eq_skip)]
    aux_data3: String,
}

I want the hash method to only use id, and name and no others.

The serde library allows something like this for serialization.

kmdreko
  • 42,554
  • 6
  • 57
  • 106
willir
  • 599
  • 1
  • 4
  • 15
  • Related [How do I implement `Hash` for an enum with a special case?](/q/69186841/2189130) There is a crate called [derivative](https://crates.io/crates/derivative) that provides additional attribute-based custom implementations for standard traits. – kmdreko Sep 20 '22 at 20:18

2 Answers2

6

No, there is no such feature in Rust at this moment. What I would suggest is to use the implementation for tuples available for these traits, like this:

use std::hash::{Hash, Hasher};

#[derive(Debug)]
struct MyStruct {
    id: i32,
    name: String,
    aux_data1: f64,
    aux_data2: f64,
    aux_data3: String,
}

impl Hash for MyStruct {
    fn hash<H>(&self, state: &mut H) where H: Hasher {
        (&self.id, &self.name).hash(state);
    }
}

impl PartialEq for MyStruct {
    fn eq(&self, other: &Self) -> bool {
        (&self.id, &self.name) == (&other.id, &other.name)
    }
}

Edit: or as @Shepmaster suggested in a comment below, you can create a key function which returns a tuple of all useful fields and use it.

impl MyStruct {
    fn key(&self) -> (&i32, &String) {
        (&self.id, &self.name)
    }
}

impl Hash for MyStruct {
    fn hash<H>(&self, state: &mut H) where H: Hasher {
        self.key().hash(state);
    }
}

impl PartialEq for MyStruct {
    fn eq(&self, other: &Self) -> bool {
        self.key() == other.key()
    }
}
Dogbert
  • 212,659
  • 41
  • 396
  • 397
  • 3
    When doing this, I've found it useful to create a `key` method that returns the tuple which is then used to keep `hash` and `eq` (and whatever else) all synchronized in order and count. – Shepmaster Apr 11 '16 at 16:01
  • @Shepmaster thanks, that seems to be a good idea, especially when you want to include > 2 fields. – Dogbert Apr 11 '16 at 16:23
1

This is possible by using derivative.

Example:

use derivative::Derivative;

#[derive(Derivative)]
#[derivative(Hash, PartialEq)]
struct Foo {
    foo: u8,
    #[derivative(Hash="ignore")]
    #[derivative(PartialEq="ignore")]
    bar: u8,
}
Sam Denty
  • 3,693
  • 3
  • 30
  • 43