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');
Why is the default type/inference behavior different between Foo and HashMap? Does the hashmap use some compiler magic?
let foo: Foo<_> = Foo::new();works fine, sinceTcan be inferred. This looks like it does not provide any additional information, but in fact it does – explicitly omitting the second parameter to the type constructor tells the compiler to use the default value. The code without any type annotation behaves likelet foo: Foo<_, _> = Foo::new();, which fails with the same error. - Sven Marnach