So I am currently using
rustc 1.36.0-nightly (8dd4aae9a 2019-05-04)
and in my lib.rs I enabled
#![feature(specialization)]
And in a module of my library crate, I have the following, which does not compile. From my understanding it should compile, even without specialization
but it does not - in either case.
use std::hash::{Hash,Hasher};
#[derive(Debug, Copy, Clone,PartialEq,Eq)]
struct HashKey<T>(T);
//default
impl<T : Hash> Hash for HashKey<T> {
fn hash<H>(&self, state: &mut H)
where H : Hasher
{
self.0.hash(state)
}
}
impl Hash for HashKey<f32> {
fn hash<H>(&self, state: &mut H)
where H : Hasher
{
unsafe { std::mem::transmute::<f32,u32>(self.0) }.hash(state)
}
}
impl Hash for HashKey<f64> {
fn hash<H>(&self, state: &mut H)
where H : Hasher
{
unsafe { std::mem::transmute::<f64,u64>(self.0) }.hash(state)
}
}
As we all know, f32
as well as f64
are neither Eq
nor Hash
because of the NaN
problem as discussed for example in this question. Using the unsafe reinterpret_cast<u32>
workaround as I do not care about Nan
in my case.
So, I have an impl of trait Hash for any HashKey<T> where T : Hash
and I have impls for both f32
and f64
which are as pointed out not Hash
. As such, it is not even a specialization as those 3 impls cover orthogonal cases.
Despite all that wonderful logic, I get the error:
conflicting implementations of trait `std::hash::Hash` for type `naive::HashKey<f32>`:
conflicting implementation for `naive::HashKey<f32>`
note: upstream crates may add new impl of trait `std::hash::Hash` for type `f32` in future versionsrustc(E0119)
naive.rs(10, 1): first implementation here
naive.rs(18, 1): conflicting implementation for `naive::HashKey<f32>`
Which leads to the questions:
Am I doing something wrong? How to do it right? Why is this a problem in the first place, given those impls refer to sets of types with no overlap?