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);
}
Run Code Online (Sandbox Code Playgroud)
我正在写关于这种行为的利用代码raw_entry的API HashMap。具体来说,我使用了一个 HashMap,其中键是枚举,但为了减少冗余分配,我想使用这些枚举的“借用”版本进行查找。
换句话说,在下面的代码中,我确实需要保证两个断言都会成功,而不管使用的是什么Hasher实现。在我看来,这将取决于和的Hash实现提供的保证。Stringstr
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);
}
}
Run Code Online (Sandbox Code Playgroud)
是否记录了有关此类保证的任何地方?我认为必须提供此类保证(否则我认为无法正确实现 的contains_key()方法HashMap,因为参数可以是密钥的任何借用形式),但我无法在任何地方找到此保证。
Fra*_*gné 10
是的。这是有保证的,因为String实现了Borrow<str>.
实施合同的一部分Borrow是:
此外,在为其他特性提供实现时,需要考虑它们是否应该与底层类型的那些特性相同,因为它们充当了底层类型的表示。通用代码通常
Borrow<T>在依赖于这些附加特征实现的相同行为时使用。这些 trait 可能会作为额外的 trait bound 出现。特别是
Eq,Ord并且Hash对于借用和拥有的值必须等效:x.borrow() == y.borrow()应该给出与 相同的结果x == y。
在标准库中,Borrow特性用于HashMap::get. Borrow可以将 a 传递&str给geta HashMap<String, _>。自然地,为了使其工作,&String并且&str必须为相同的字符串产生相同的散列,因此需要Borrow. 该要求在文档中重复用于HashMap::get:
关键可能是地图的主要类型的任何借来的形式,但
Hash并Eq借用表格上必须匹配的密钥类型。
Traits 无法在代码中定义这样的要求,因此可能存在不符合要求的实现,因为编译器无法强制执行这些要求。但是,这样的实现会破坏HashMap.