我有一个结构,除其他数据外,还有一个唯一的id
:
struct Foo {
id: u32,
other_data: u32,
}
我想使用id
作为键并将其保留在结构中:
use std::collections::HashSet;
use std::hash::{Hash, Hasher};
impl PartialEq for Foo {
fn eq(&self, other: &Foo) -> bool {
self.id == other.id
}
}
impl Eq for Foo {}
impl Hash for Foo {
fn hash<H: Hasher>(&self, state: &mut H) {
self.id.hash(state);
}
}
这有效:
pub fn bar() {
let mut baz: HashSet<Foo> = HashSet::new();
baz.insert(Foo {
id: 1,
other_data: 2,
});
let other_data = baz.get(&Foo {
id: 1,
other_data: 0,
}).unwrap()
.other_data;
println!("other_data: {}", other_data);
}
有没有办法写baz.get(1).unwrap().other_data;
代替baz.get(&Foo { id: 1, other_data: 0 }).unwrap().other_data;
?
替代方案可能是HashMap
,其中密钥包含在struct
中。但是,我不能在结构中包含id
,而在id
中使用重复的key
。
答案 0 :(得分:6)
当您查看HashSet::get
的签名时,您会注意到它比您预期的要复杂一点:
fn get<Q: ?Sized>(&self, value: &Q) -> Option<&T>
where
T: Borrow<Q>,
Q: Hash + Eq,
这样做正是为了解决您的问题。 get
接受对可以从集合中的类型(&Q
)借用的任何类型(T: Borrow<Q>
)的引用。 T
应该被理解为&#34;我的类型&#34;并且Q
应该被理解为&#34;查询类型&#34;。
因此,您需要为您的类型实施Borrow
:
use std::borrow::Borrow;
use std::collections::HashSet;
use std::hash::{Hash, Hasher};
type Id = u32;
#[derive(Debug, Eq)]
struct Foo {
id: Id,
other_data: u32,
}
impl PartialEq for Foo {
fn eq(&self, other: &Foo) -> bool {
self.id == other.id
}
}
impl Hash for Foo {
fn hash<H: Hasher>(&self, state: &mut H) {
self.id.hash(state);
}
}
impl Borrow<Id> for Foo {
fn borrow(&self) -> &Id {
&self.id
}
}
fn main() {
let mut baz = HashSet::new();
baz.insert(Foo {
id: 1,
other_data: 2,
});
let other_data = baz.get(&1).unwrap().other_data;
println!("other_data: {}", other_data);
}
另见: