为什么在存在类型参数默认值的情况下,对于HashMap和我自己的结构,类型推断的行为会有所不同?

Luk*_*odt 6 rust

我有一个带有两个类型参数的结构,其中一个具有默认类型:

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);
Run Code Online (Sandbox Code Playgroud)

上面的代码导致:

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
Run Code Online (Sandbox Code Playgroud)

我不明白为什么这里不使用默认类型。请注意,let foo: Foo<u32> = Foo::new();已经说过了-无需指定参数F。但是为什么要指定T?所以我已经很困惑。

但是后来我想起了所有这些HashMap!定义为struct HashMap<K, V, S = RandomState>。而且我不需要指定任何东西。例如,这有效:

use std::collections::HashMap;

let mut map = HashMap::new();
map.insert(0u32, 'x');
Run Code Online (Sandbox Code Playgroud)

操场上的一切

为什么Foo和之间的默认类型/推断行为不同HashMap哈希图是否使用了一些编译器魔术?

Tim*_*ann 8

HashMap::new is defined this way:

impl<K: Hash + Eq, V> HashMap<K, V, RandomState> {
    pub fn new() -> HashMap<K, V, RandomState> {
        Default::default()
    }
}
Run Code Online (Sandbox Code Playgroud)

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) {}
}
Run Code Online (Sandbox Code Playgroud)

Playground

Note: Default can be used for a custom BuildHasher:

impl<K, V, S> Default for HashMap<K, V, S>
Run Code Online (Sandbox Code Playgroud)

  • 简而言之:无法推论的F是隐含的参数F,而不是结构的参数F。如果将参数重命名为impl到其他名称,则从错误消息中可以清楚地看出。 (2认同)