Reputation: 1302
I have a data structure that looks something like this:
pub struct X<K> {
hasher: Box<std::hash::Hasher>,
phantom: std::marker::PhantomData<K>,
}
And this is used as follows:
impl<K: std::hash::Hash> Trait<K> for X<K> {
fn function(&mut self, key: &K) -> usize {
...
key.hash(&mut *self.hasher);
...
}
}
I am getting the following compiler error in the nightly:
The trait
std::hash::Hasher
is not implemented forstd::boxed::Box<std::hash::Hasher + 'static>
Another approach is to use key.hash(self.hasher.deref_mut())
, which triggers the following error:
std::hash::Hasher + 'static
does not have a constant size known at compile-time
Both errors are in the hash
call. I find it strange that std::hash::Hasher
is not implemented for Box
, but I wonder if this is not something done to protect me from myself. Aside from that, it seems weird that the deref_mut
error complains about size known at compile time, considering that the Box
should be a fixed size structure.
I know that a way to fix this would be to use a template parameter, but I am avoiding this since X
will be used in other data structures which wouldn't need the parameter, and that would mean I would have to pass around an unnecessary parameter. It seems that this is the approach taken by HashMap
, as it uses the RandomState
template parameter, but I would prefer to avoid that if possible.
Upvotes: 2
Views: 334
Reputation: 430673
I find it strange that
std::hash::Hasher
is not implemented forBox
I assume you mean for Box<T> where T: std::hash::Hasher
. I don't know why it wouldn't be implemented, but it's probably just because no one has yet.
it seems weird that the
deref_mut
error complains about size known at compile time
The problem is that the generic type H
has the implicit Sized
bound (everything does by default):
fn hash<H>(&self, state: &mut H)
where
H: Hasher;
You'd need it to say:
fn hash<H>(&self, state: &mut H)
where
H: ?Sized + Hasher;
Again, I don't see any reason it couldn't be changed to do this, it's just most likely that no one needed it to.
You can add a newtype to work around the problem:
use std::hash;
pub struct X<K> {
hasher: BoxedHasher,
phantom: std::marker::PhantomData<K>,
}
struct BoxedHasher(Box<hash::Hasher>);
impl hash::Hasher for BoxedHasher {
fn finish(&self) -> u64 {
self.0.finish()
}
fn write(&mut self, bytes: &[u8]) {
self.0.write(bytes)
}
}
impl<K> X<K>
where
K: hash::Hash,
{
fn function(&mut self, key: &K) -> usize {
key.hash(&mut self.hasher);
0
}
}
Upvotes: 2