I have some structs that implement both Hash
and MyTrait
. I'm using them as &dyn MyTrait
trait objects.
Now I want &dyn MyTrait
to also implement Hash
. I've tried a few things:
Naively,
trait MyTrait: Hash {}
:the trait `MyTrait` cannot be made into an object
Then I tried this:
impl Hash for dyn MyTrait { fn hash<H: Hasher>(&self, hasher: &mut H) { // ... }}
but I need to delegate to the
hash
method of the concrete type ofself
, I think.So the naive next step is to put this on
MyTrait
:fn my_hash<H: Hasher>(&self, hasher: &mut H);
which brings me right back to the first point.
I read something about using a trait object instead of generic parameter, which sounds smart, so I put this on
MyTrait
fn my_hash(&self, hasher: &mut H);
Then I need to actually implement this. Preferably not by hand for every trait:
impl<T: 'static + Hash> MyTrait for T { fn as_any(&self) -> &dyn Any { self as &dyn Any } fn my_hash(&self, hasher: &mut Hasher) { self.as_any().downcast_ref::<T>().unwrap().hash(hasher) }}
but then
the trait bound `std::hash::Hasher: std::marker::Sized` is not satisfied`std::hash::Hasher` does not have a constant size known at compile-time
So I'd have to downcast
Hasher
…If downcasting
Hasher
is the way, I need a generic parameterH
that can convert to anAny
Hasher
, Let's try:trait AnyHasher { fn as_any(&self) -> &dyn Any;}impl<H: 'static + Hasher> AnyHasher for H { fn as_any(&self) -> &dyn Any { self as &dyn Any }}
and then to downcast
impl<T: 'static + Hash, H: 'static + Hasher> MyTrait for T { // ... fn my_hash(&self, hasher: &mut AnyHasher) { let h = hasher.as_any().downcast_ref::<H>().unwrap(); self.as_any().downcast_ref::<T>().unwrap().hash(h) }}
but alas
the type parameter `H` is not constrained by the impl trait, self type, or predicates
which I guess is true, but then I'm stuck. (Also it seems kind of ridiculous so far).
Can this can be done? If so, how?
I previously asked about PartialEq
for trait objects, which was hard because information the concrete type of the trait object is needed. That was solved with downcasting, but I didn't manage to apply that solution here.