Often times I want to hash a custom struct based on some subset of its fields. It's tedious to implement Hash and PartialEq/Eq for all these structs separately, so I would like to create a separate trait Hashable, which my structs can implement to specify the fields to hash. Here's what I have:
However, when I try to use MyStruct, it says that it does not implement Hash. What am I doing wrong, and what I can do to achieve what I want? Thanks in advance.
dyn Hashable<…> is a distinct type from any struct that implements Hashable, so implementing traits for it won’t implement those same traits for the struct. What you really want is generics, but Rust’s orphan rules prevent it from working:
use core::hash::Hasher;
use core::hash::Hash;
pub trait Hashable {
type HashKey: Hash + Eq;
fn hash_key(&self) > Self::HashKey;
}
impl<T, K: Hash + Eq> Hash for T where T: Hashable<HashKey = K> {
fn hash<H>(&self, state: &mut H)
where
H: Hasher,
{
self.hash_key().hash(state);
}
}
impl<T, K: Hash + Eq> PartialEq for T where T: Hashable<HashKey = K> {
fn eq(&self, other: &Self) > bool {
self.hash_key() == other.hash_key()
}
}
impl<T, K: Hash + Eq> Eq for T where T: Hashable<HashKey = K> {}
Compiling playground v0.0.1 (/playground)
error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct<T>`)
> src/lib.rs:9:6

9  impl<T, K: Hash + Eq> Hash for T where T: Hashable<HashKey = K> {
 ^ type parameter `T` must be used as the type parameter for some local type

= note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local
= note: only traits defined in the current crate can be implemented for a type parameter
error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct<T>`)
> src/lib.rs:17:6

17  impl<T, K: Hash + Eq> PartialEq for T where T: Hashable<HashKey = K> {
 ^ type parameter `T` must be used as the type parameter for some local type

= note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local
= note: only traits defined in the current crate can be implemented for a type parameter
error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct<T>`)
> src/lib.rs:22:6

22  impl<T, K: Hash + Eq> Eq for T where T: Hashable<HashKey = K> {}
 ^ type parameter `T` must be used as the type parameter for some local type

= note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local
= note: only traits defined in the current crate can be implemented for a type parameter
For more information about this error, try `rustc explain E0210`.
error: could not compile `playground` due to 3 previous errors
_{Sorry for not providing a solution; I’m short on time right now}