I have a struct with two type parameters, one of which has a default type:
use std::marker::PhantomData;
struct Foo<T, F = ()>(PhantomData<(T, F)>);
impl<T, F> Foo<T, F> {
fn new() -> Self { Self(PhantomData) }
fn foo(&self, _: T) {}
}
let foo = Foo::new();
foo.foo(0u32);
The code above leads to:
error[E0282]: type annotations needed
--> src/main.rs:17:15
|
17 | let foo = Foo::new();
| --- ^^^^^^^^ cannot infer type for `F`
| |
| consider giving `foo` a type
I don't understand why the default type is not used here. Note that saying let foo: Foo<u32> = Foo::new();
already works -- so there is no need to specify the parameter F
. But why specify T
? So I was already confused.
But then I remembered that all of this works with HashMap
! It is defined as struct HashMap<K, V, S = RandomState>
. And I never needed to specify anything. For example, this works:
use std::collections::HashMap;
let mut map = HashMap::new();
map.insert(0u32, 'x');
(Everything on Playground)
Why is the default type/inference behavior different between Foo
and HashMap
? Does the hashmap use some compiler magic?
HashMap::new
is defined this way:
impl<K: Hash + Eq, V> HashMap<K, V, RandomState> {
pub fn new() -> HashMap<K, V, RandomState> {
Default::default()
}
}
RandomState
is provided for S
for new
. Your code would look like this for the same behavior:
impl<T> Foo<T, ()> {
fn new() -> Self { Self(PhantomData) }
fn foo(&self, _: T) {}
}
Playground
Note: Default
can be used for a custom BuildHasher
:
impl<K, V, S> Default for HashMap<K, V, S>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With