Rust 引用没有实现 Eq/Hash?如何将它们用作哈希映射键?
Rust references don't implement Eq/Hash? How to use them as hash map key?
我想构建一个 hashmap,其中的键是引用。我希望这些引用的相等性意味着引用相等,即两个引用借用同一个对象。
use std::collections::hash_map::HashMap;
struct SomeKey();
struct SomeValue();
fn main() {
let m = HashMap::<&SomeKey, SomeValue>::new();
let t = SomeKey();
m.get(&t);
}
不幸的是,这失败了,编译器告诉我 &SomeKey
没有实现 Hash
/Eq
.
error[E0599]: the method `get` exists for struct `HashMap<&SomeKey, SomeValue>`, but its trait bounds were not satisfied
--> src/main.rs:10:7
|
10 | m.get(&t);
| ^^^ method cannot be called on `HashMap<&SomeKey, SomeValue>` due to unsatisfied trait bounds
|
= note: the following trait bounds were not satisfied:
`&SomeKey: Eq`
`&SomeKey: Hash`
我注意到,如果我为 SomeKey
实现 Eq+Hash
,那么它就可以工作,但这可能会使用底层对象相等性,这不是我想要的。
有没有一种方法可以将引用用作基于指针相等性的哈希映射键?
您可以使用 by_address
crate。它包装任何 pointer/reference 类型以按地址而不是按内容比较对象。
use std::collections::hash_map::HashMap;
use by_address::ByAddress;
struct SomeKey();
struct SomeValue();
fn main() {
let mut m = HashMap::<ByAddress<&SomeKey>, SomeValue>::new();
let t1 = SomeKey();
let t2 = SomeKey();
m.insert(ByAddress(&t1), SomeValue());
assert!(m.get(&ByAddress(&t1)).is_some());
assert!(m.get(&ByAddress(&t2)).is_none());
}
这可以通过在引用上实现 Hash
和 Eq
然后使用 std::ptr
中的函数来执行操作来处理。将引用转换为 usize
然后对其进行操作也可以。您只需确保在 impl
中取消引用一次,因为 &Self
的类型为 &&SomeKey
.
use std::collections::HashMap;
struct SomeKey();
struct SomeValue();
impl<'a> PartialEq for &'a SomeKey{
fn eq(&self, other:&Self) -> bool{
std::ptr::eq(*self, *other)
}
}
impl<'a> Eq for &'a SomeKey{}
use std::hash::Hash;
use std::hash::Hasher;
impl<'a> Hash for &'a SomeKey {
fn hash<H: Hasher>(&self, state: &mut H) {
std::ptr::hash(*self, state)
}
}
fn main() {
let m = HashMap::<&SomeKey, SomeValue>::new();
let t = SomeKey();
m.get(&&t);
}
我想构建一个 hashmap,其中的键是引用。我希望这些引用的相等性意味着引用相等,即两个引用借用同一个对象。
use std::collections::hash_map::HashMap;
struct SomeKey();
struct SomeValue();
fn main() {
let m = HashMap::<&SomeKey, SomeValue>::new();
let t = SomeKey();
m.get(&t);
}
不幸的是,这失败了,编译器告诉我 &SomeKey
没有实现 Hash
/Eq
.
error[E0599]: the method `get` exists for struct `HashMap<&SomeKey, SomeValue>`, but its trait bounds were not satisfied
--> src/main.rs:10:7
|
10 | m.get(&t);
| ^^^ method cannot be called on `HashMap<&SomeKey, SomeValue>` due to unsatisfied trait bounds
|
= note: the following trait bounds were not satisfied:
`&SomeKey: Eq`
`&SomeKey: Hash`
我注意到,如果我为 SomeKey
实现 Eq+Hash
,那么它就可以工作,但这可能会使用底层对象相等性,这不是我想要的。
有没有一种方法可以将引用用作基于指针相等性的哈希映射键?
您可以使用 by_address
crate。它包装任何 pointer/reference 类型以按地址而不是按内容比较对象。
use std::collections::hash_map::HashMap;
use by_address::ByAddress;
struct SomeKey();
struct SomeValue();
fn main() {
let mut m = HashMap::<ByAddress<&SomeKey>, SomeValue>::new();
let t1 = SomeKey();
let t2 = SomeKey();
m.insert(ByAddress(&t1), SomeValue());
assert!(m.get(&ByAddress(&t1)).is_some());
assert!(m.get(&ByAddress(&t2)).is_none());
}
这可以通过在引用上实现 Hash
和 Eq
然后使用 std::ptr
中的函数来执行操作来处理。将引用转换为 usize
然后对其进行操作也可以。您只需确保在 impl
中取消引用一次,因为 &Self
的类型为 &&SomeKey
.
use std::collections::HashMap;
struct SomeKey();
struct SomeValue();
impl<'a> PartialEq for &'a SomeKey{
fn eq(&self, other:&Self) -> bool{
std::ptr::eq(*self, *other)
}
}
impl<'a> Eq for &'a SomeKey{}
use std::hash::Hash;
use std::hash::Hasher;
impl<'a> Hash for &'a SomeKey {
fn hash<H: Hasher>(&self, state: &mut H) {
std::ptr::hash(*self, state)
}
}
fn main() {
let m = HashMap::<&SomeKey, SomeValue>::new();
let t = SomeKey();
m.get(&&t);
}