来自这里的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中,我无法将dict放入集合中,因此BTreeMap的行为令我惊讶.

有人能解释一下吗?

推荐答案

原因是BTreeMap有一个确定的迭代顺序,而HashMap没有.引用Hash个特征中的文档,

在实现Hash和Eq时,以下属性保持不变是很重要的:

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

换句话说,如果两个键相等,它们的散列也必须相等.HashMap和HashSet都依赖于这种行为.

由于HashMap的迭代顺序是不确定的,因此无法保证这种行为,因此每当输入不同的HashMap时,数据都会以不同的顺序馈送到Hasher,即使它们包含相同的元素,也会打破Hash的约定,导致在HashSetHashMap中使用时发生不好的事情.

然而,BTreeMap的全部意义在于它是一个有序映射,这意味着它的迭代以有序的顺序发生,这是完全确定的,这意味着Hash的契约可以得到满足,因此提供了一个实现.

请注意,这两种行为都不同于Python的Dict,后者按插入顺序迭代.

Rust相关问答推荐

即使参数和结果具有相同类型,fn的TypId也会不同

如何在rust中有条件地分配变量?

使用元组执行条件分支的正确方法

如何装箱生命周期相关联的两个对象?

制作一片连续整数的惯用Rust 方法?

如何实现泛型枚举的`Serde::Desialize`特性

是否可以在不切换到下一个位置的情况下获得迭代器值:

在Rust中,Box:ed struct 与普通 struct 在删除顺序上有区别吗?

使用关联类型重写时特征的实现冲突

正在将带有盒的异步特征迁移到新的异步_fn_in_特征功能

Rust中WPARAM和VIRTUAL_KEY的比较

对reqwest提供的这种嵌套JSON struct 进行反序列化

Rust ECDH 不会产生与 NodeJS/Javascript 和 C 实现相同的共享密钥

存储返回 impl Trait 作为特征对象的函数

有什么办法可以追踪泛型的单态化过程吗?

不安全块不返回预期值

Rust:`sort_by` 多个条件,冗长的模式匹配

Rust 生命周期:这两种类型声明为不同的生命周期

在 Rust 中如何将值推送到枚举 struct 内的 vec?

将文件的第一行分别读取到文件的其余部分的最有效方法是什么?