Почему BTreeMap хешируется, а не HashMap?

Исходя из Python здесь.

Мне интересно, почему BTreeMap можно хэшировать. Я не удивлен, что Hashmap нет, но я не понимаю, почему BTreeMap.

Например, я могу сделать так:

let mut seen_comb: HashSet<BTreeMap<u8, u8>> = HashSet::new();
seen_comb.insert(BTreeMap::new());

Но я не могу этого сделать:

let mut seen: HashSet<HashMap<u8, u8>> = HashSet::new();
seen.insert(HashMap::new());

Потому что я получаю:

error[E0599]: the method `insert` exists for struct `HashSet<HashMap<u8, u8>>`, but its trait bounds were not satisfied
   --> src/main.rs:14:10
    |
14  |     seen.insert(HashMap::new());
    |          ^^^^^^ method cannot be called on `HashSet<HashMap<u8, u8>>` due to unsatisfied trait bounds
    |
   ::: /home/djipey/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/collections/hash/map.rs:209:1
    |
209 | pub struct HashMap<K, V, S = RandomState> {
    | ----------------------------------------- doesn't satisfy `HashMap<u8, u8>: Hash`
    |
    = note: the following trait bounds were not satisfied:
            `HashMap<u8, u8>: Hash`

В Python я не могу поместить словарь в набор, поэтому поведение BTreeMap меня удивляет.

Может ли кто-нибудь дать объяснение здесь?

Это всего лишь предположение, но порядок хэширования элементов влияет на результаты, а HashMap не имеет детерминированного порядка. Даже если у двух HashMap одинаковые элементы, порядок может быть разным.

kmdreko 18.03.2022 21:03
Почему Python в конце концов умрет
Почему Python в конце концов умрет
Последние 20 лет были действительно хорошими для Python. Он прошел путь от "просто языка сценариев" до основного языка, используемого для написания...
2
1
76
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Причина в том, что BTreeMap имеет детерминированный порядок итераций, а HashMap — нет. Чтобы процитировать документы из признака Hash,

When implementing both Hash and Eq, it is important that the following property holds:

k1 == k2 -> hash(k1) == hash(k2)

In other words, if two keys are equal, their hashes must also be equal. HashMap and HashSet both rely on this behavior.

Невозможно гарантировать такое поведение, поскольку порядок итерации HashMap недетерминирован, поэтому данные будут подаваться в Hasher в другом порядке всякий раз, когда вводится другой HashMap, даже если они содержат одни и те же элементы, нарушая контракт Hash и вызывать плохие вещи при использовании в HashSet или HashMap.

Однако весь смысл BTreeMap в том, что это упорядоченная карта, то есть итерация по ней происходит в отсортированном порядке, что является полностью детерминированным, то есть контракт Hash может быть выполнен, поэтому предоставляется реализация.

Обратите внимание, что оба эти поведения отличаются от Python Dict, который выполняет итерацию по порядку вставки.

Ок, понятно, спасибо. Я чуть было не спросил, почему тогда Python dicts не хэшируется (хешируемый объект в python должен соответствовать тем же критериям), но ваш комментарий к порядку вставки прояснил это. В Python, поскольку словари упорядочены по порядку вставки, у меня может быть 2 словаря с одинаковым содержимым, но с другим порядком итерации.

JPFrancoia 19.03.2022 12:57

Другие вопросы по теме