Почему вывод типа ведет себя по-разному для `HashMap` и моей собственной структуры при наличии параметра типа по умолчанию? - PullRequest
6 голосов
/ 10 апреля 2019

У меня есть структура с двумя параметрами типа, один из которых имеет тип по умолчанию:

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);

Приведенный выше код приводит к:

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

Я не понимаю, почемутип по умолчанию здесь не используется.Обратите внимание, что поговорка 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');

( Все на игровой площадке )

Почему поведение типа / логического вывода по умолчанию отличается между Foo и HashMap? Использует ли hashmap какую-то магию компилятора?

1 Ответ

8 голосов
/ 10 апреля 2019

HashMap::new определяется следующим образом:

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

RandomState предоставляется для S для new. Ваш код будет выглядеть так для того же поведения:

impl<T> Foo<T, ()> {
    fn new() -> Self { Self(PhantomData) }
    fn foo(&self, _: T) {}
}

Детская площадка

Примечание: Default можно использовать для пользовательских BuildHasher:

impl<K, V, S> Default for HashMap<K, V, S>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...