Hello everyone.
I'm learning Rust for almost a month now, and just as I feel like I've grasped all the concepts, something new pops up.
I'm having a problem with passing a std::hash::Hasher
trait object into the std::hash::Hash::hash
method. Its signature takes a mutable reference to a generic Hasher
:
fn hash<H: Hasher>(&self, state: &mut H);
I have a function that takes a dyn Hasher
:
fn hash_something_with(hasher: &mut dyn Hasher) { ... }
It seems obvious to me, that state
in Hash::hash
and hasher
in my function are of the same type, so I can just pass it through:
fn hash_something_with(hasher: &mut dyn Hasher) {
123i32.hash(hasher);
}
However, it doesn't compile:
error[E0277]: the size for values of type `dyn std::hash::Hasher` cannot be known at compilation time
--> src/main.rs:6:16
|
6 | 123i32.hash(hasher);
| ^^^^^^ doesn't have a size known at compile-time
|
= help: the trait `std::marker::Sized` is not implemented for `dyn std::hash::Hasher`
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
This would be reasonable, if I hadn't passed it as a reference. It almost seems to me that compiler implicitly dereferences hasher
before passing it to hash
.
But if I do:
fn hash_something_with(hasher: &mut dyn Hasher) {
123i32.hash(&mut *hasher);
}
... nothing changes.
If I make my argument mutable and then take another reference of it, it suddenly works:
fn hash_something_with(mut hasher: &mut dyn Hasher) { // passed in a mutable reference to a mutable Hasher
123i32.hash(&mut hasher); // passing in a mutable reference to a mutable variable that is a mutable Hasher...
}
And I can't understand why, because &mut hasher
should be a reference to a reference (&mut &mut dyn Hasher
), and it doesn't match Hash::hash
signature. And to top it all off, if I use an std::hash::BuildHasher
and build an instance of std::hash::Hasher
inside of my function, passing a reference to that instance also works! Even though it's passed as a direct reference.
I'm totally lost here. Any help will be greatly appreciated.
Here's the full code for demonstration and a link to playground:
use std::hash::{Hash, Hasher, BuildHasher};
// DOESN'T WORK:
// fn demo1(hasher: &mut dyn Hasher) {
// 123i32.hash(hasher);
// }
// WORKS:
fn demo2(mut hasher: &mut dyn Hasher) { // passed in a mutable reference to a mutable Hasher
123i32.hash(&mut hasher); // passing in a mutable reference to a mutable variable that is a mutable Hasher...
}
// STRANGELY WORKS:
fn demo3<H: Hasher>(factory: &dyn BuildHasher<Hasher = H>) {
let mut hasher = factory.build_hasher(); // creating a mutable Hasher
123i32.hash(&mut hasher); // passing in a mutable reference to i32::hash()
}
fn main() {
let factory = std::collections::hash_map::RandomState::new();
let mut hasher = factory.build_hasher();
demo2(&mut hasher);
demo3(&factory);
}