Rust引用未实现Eq/Hash,如何将其作为基于指针相等的HashMap键?
基于指针相等的引用作为HashMap键的实现方案
核心思路
Rust标准库对引用类型&T的Eq和Hash实现默认会代理到底层T类型的对应实现,因此会基于对象内容做相等性判定,不符合你的需求。我们可以自定义一个引用包装类型,手动实现Eq和Hash,逻辑完全基于指针的内存地址:
完整实现代码
use std::hash::{Hash, Hasher}; use std::collections::HashMap; use std::ptr; // 自定义引用包装类,基于指针地址判等 #[derive(Copy, Clone, Debug)] struct ByAddress<'a, T>(&'a T); impl<'a, T> PartialEq for ByAddress<'a, T> { fn eq(&self, other: &Self) -> bool { // 直接比较两个指针是否指向同一个内存地址 ptr::eq(self.0, other.0) } } impl<'a, T> Eq for ByAddress<'a, T> {} impl<'a, T> Hash for ByAddress<'a, T> { fn hash<H: Hasher>(&self, state: &mut H) { // 对指针地址做哈希,而非对象内容 (self.0 as *const T).hash(state); } } // 使用示例 struct SomeKey(); struct SomeValue(); fn main() { let mut m = HashMap::new(); let t1 = SomeKey(); let t2 = SomeKey(); // 插入t1的引用 m.insert(ByAddress(&t1), SomeValue()); // 用同一块内存的引用查找,命中 assert!(m.get(&ByAddress(&t1)).is_some()); // 用不同内存的同结构对象查找,不命中 assert!(m.get(&ByAddress(&t2)).is_none()); }
注意事项
- 包装类型
ByAddress的生命周期和原始引用绑定,借用检查会自动保证HashMap不会持有悬垂引用,所有插入的键指向的对象都必须比HashMap存活更久。 - 如果你的场景中使用的是
Box<T>、Rc<T>等智能指针,只需要修改包装逻辑取内部指针地址即可,整体实现思路一致。
内容的提问来源于stack exchange,提问作者Heinzi
相关产品推荐
相关产品推荐

