在使用使用&'static str
作为键类型的HashMap
时,我创建了一个newtype来按指针而不是按字符串内容进行散列,以减少开销.
pub struct StaticStr(&'static str);
impl Hash for StaticStr {
fn hash<H: Hasher>(&self, state: &mut H) {
self.0.as_ptr().hash(state)
}
}
impl PartialEq for StaticStr {
fn eq(&self, other: &Self) -> bool {
self.0.as_ptr() == other.0.as_ptr()
}
}
impl Eq for StaticStr {}
事实证明,这并不是始终如一的工作,如以下示例所示.
pub type MyMap = HashMap<StaticStr, u8>;
pub const A: &str = "A";
pub fn make_map() -> MyMap {
let mut map = MyMap::new();
map.insert(StaticStr(A), 1);
map
}
pub fn get_value(control: &MyMap) -> Option<u8> {
control.get(&StaticStr(A)).cloned()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
pub fn map_made_in_lib() {
let map = make_map();
assert_eq!(get_value(&map), Some(1));
}
#[test]
pub fn map_made_in_test() {
// Same as make_map()
let mut map = MyMap::new();
map.insert(StaticStr(A), 1);
// This check fails
assert_eq!(get_value(&map), Some(1));
}
}
注意,在第一个测试中,字符串常数A
仅直接用于lib crate .在第二次测试中,A
直接用于lib crate 和测试 crate .我发现,尽管两个测试使用相同的字符串常量,但指针是不同的,这取决于哪个 crate 按名称引用字符串常量.这在我创建的minimal reproduction个例子中得到了证明.我原本希望字符串文字对于定义它的 crate 只包含一次,或者至少链接器足够智能,能够消除字符串文字的重复.这种行为有什么原因吗?