拥有和借用的字符串是否保证可以哈希为相同的值?

问题描述 投票:2回答:1

Stringstr都实现Hash,因此我们可以对它们之一进行哈希处理。似乎拥有和借用的字符串当前都哈希为相同的值,因此此断言成功:

use std::hash::Hash;
use std::hash::Hasher;
use std::collections::hash_map::DefaultHasher;
pub fn main() {
    let hash1 = {
        let x: String = "abc".to_owned();
        let mut hasher = DefaultHasher::new();
        x.hash(&mut hasher);
        hasher.finish()
    };
    let hash2 = {
        let x: &str = "abc";
        let mut hasher = DefaultHasher::new();
        x.hash(&mut hasher);
        hasher.finish()
    };
    assert!(hash1 == hash2);
}

[我正在利用raw_entryHashMap API中的这种行为编写代码。具体来说,我使用的是键为枚举的HashMap,但是为了减少冗余分配,我想使用这些枚举的“借用”版本进行查找。

换句话说,在下面的代码中,我确实需要确保两个断言都将成功,无论使用哪种Hasher实现。在我看来,这将取决于HashStringstr实现提供的保证。

use std::hash::Hash;
use std::hash::Hasher;
use std::collections::hash_map::DefaultHasher;
pub fn main() {
    {
        #[derive(Hash)]
        enum E1 {
            First(i32),
            Second(String),
        }
        #[derive(Hash)]
        enum E2<'a> {
            First(i32),
            Second(&'a str),
        }
        let hash1 = {
            let x: E1 = E1::First(100);
            let mut hasher = DefaultHasher::new();
            x.hash(&mut hasher);
            hasher.finish()
        };
        let hash2 = {
            let x: E2 = E2::First(100);
            let mut hasher = DefaultHasher::new();
            x.hash(&mut hasher);
            hasher.finish()
        };
        assert!(hash1 == hash2);
        let hash3 = {
            let x: E1 = E1::Second("abc".to_owned());
            let mut hasher = DefaultHasher::new();
            x.hash(&mut hasher);
            hasher.finish()
        };
        let hash4 = {
            let x: E2 = E2::Second("abc");
            let mut hasher = DefaultHasher::new();
            x.hash(&mut hasher);
            hasher.finish()
        };
        assert!(hash3 == hash4);
    }
}

是否有关于此类担保的任何文件?我想必须提供这样的保证(否则,我看不到正确实现contains_key()HashMap方法的方法,因为参数可以是密钥的任何借用形式),但是我找不到记录的保证任何地方。

hash rust hashmap
1个回答
1
投票

是。这是有保证的,因为String实现了Borrow<str>

Borrow的实施合同的一部分是:

此外,当为其他特征提供实现时,由于充当该基础类型的表示而需要考虑它们是否应与基础类型的行为相同。当通用代码依赖于这些附加特征实现的相同行为时,通常会使用Borrow。这些特征可能会显示为其他特征边界。

特别是Borrow<T>EqOrd对于借入和拥有的值必须是等效的:Hash应提供与x.borrow() == y.borrow()相同的结果。

在标准库中,x == y特性用于BorrowHashMap::get可以将HashMap::get传递到Borrow上的&str。自然地,为了使它起作用,getHashMap<String, _>必须为相同的字符串产生相同的哈希,因此需要&String&str的文档中重复了该要求:

密钥可以是地图密钥类型的任何借用形式,但是借用形式上的BorrowHashMap::get 必须匹配密钥类型的那些。


特质无法在代码中定义这样的要求,因此,由于编译器无法强制执行这些要求,因此可能存在不合格的实现。但是,这样的实现会破坏Hash

© www.soinside.com 2019 - 2024. All rights reserved.