I have a unique scenario where I want to use f64
as a key in a HashMap
. In particular I know the f64
will never be NaN
and I can tolerate f64
s that should be equal, but are not. So I transmute()
the f64
to u64
. However, when I pull the u64
out the HashMap
and transmute()
it back to a f64
it is a different value. Code below and on playground.
use std::collections::HashMap;
fn main() {
let x = 5.0;
let y: u64 = unsafe { std::mem::transmute(x) };
let x: f64 = unsafe { std::mem::transmute(y) };
println!("y: {}, x: {}", y, x);
let mut hash = HashMap::new();
hash.insert(y, 8);
for (y, _) in &hash {
let x: f64 = unsafe { std::mem::transmute(y) };
println!("y: {}, x: {}", y, x);
}
}
What am I missing?
When you write for (y, _) in &hash
, y
will be a reference to the key, which you will then transmute to a meaningless float.
Should you write for (&y, _) in &hash
or use *y
, you'd get the expected value.
Transmuting the wrong thing is why one should never infer the types when using transmute
, and should always avoid transmute
. In particular, for this specific transformation, there are the safe methods f64::to_bits
and f64::from_bits
. An even more idiomatic way would be to use a HashMap<FloatWrapper, Value>
where FloatWrapper
implements Ord
.