String
和str
都实现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_entry
的HashMap
API中的这种行为编写代码。具体来说,我使用的是键为枚举的HashMap,但是为了减少冗余分配,我想使用这些枚举的“借用”版本进行查找。
换句话说,在下面的代码中,我确实需要确保两个断言都将成功,无论使用哪种Hasher
实现。在我看来,这将取决于Hash
和String
的str
实现提供的保证。
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
方法的方法,因为参数可以是密钥的任何借用形式),但是我找不到记录的保证任何地方。
是。这是有保证的,因为String
实现了Borrow<str>
。
Borrow
的实施合同的一部分是:
此外,当为其他特征提供实现时,由于充当该基础类型的表示而需要考虑它们是否应与基础类型的行为相同。当通用代码依赖于这些附加特征实现的相同行为时,通常会使用
Borrow
。这些特征可能会显示为其他特征边界。特别是
Borrow<T>
,Eq
和Ord
对于借入和拥有的值必须是等效的:Hash
应提供与x.borrow() == y.borrow()
相同的结果。
在标准库中,x == y
特性用于Borrow
。 HashMap::get
可以将HashMap::get
传递到Borrow
上的&str
。自然地,为了使它起作用,get
和HashMap<String, _>
必须为相同的字符串产生相同的哈希,因此需要&String
。 &str
的文档中重复了该要求:
密钥可以是地图密钥类型的任何借用形式,但是借用形式上的
Borrow
和HashMap::get
必须匹配密钥类型的那些。
特质无法在代码中定义这样的要求,因此,由于编译器无法强制执行这些要求,因此可能存在不合格的实现。但是,这样的实现会破坏Hash
。