【发布时间】:2017-07-29 03:27:07
【问题描述】:
我有一个结构,除其他数据外,它还有一个独特的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,并且不能在 key 中使用重复的 id。
【问题讨论】:
-
我不太了解 Rust。在基于引用的语言(如 Java)中,当出现此问题时,您将使用盒装键(无论您是否喜欢在 Java 中都可以得到),并在 HashMap 输入键字段中引用它,而在对应的值对象。在像 C 或 Ada 这样允许引用/指向未装箱类型的语言中,您可以将值存储在任一位置,并将对它的引用存储在另一个位置。 Afaik Rust 集合肯定允许第一个解决方案,也许还有第二个解决方案。
-
也许使用枚举 {Key(u32), KeyAndData(u32,u32)} 并实现 hash/eq 以便您可以按键查询并获取 keyanddata?这样您就不必构建
Foo的尾部。无论如何,你没有说为什么你真的需要这个,因为你的玩具示例已经可以在没有修改的情况下工作。 -
@Gene 您的第一点有效(请参阅How can I keep a reference to a key after it has been inserted into a HashMap?),但您无法引用密钥,因为该解决方案不是内存安全的(Rust 会告诉您)-键的地址可以随着添加/删除的东西而改变,所以你会有一个悬空指针。 Rust 实际上也不够聪明,无法判断盒装的情况也很好。请参阅What's the idiomatic way to make a lookup table which uses field of the item as the key? 了解更多信息。
-
谢谢。感谢您的回复。我只阅读了 Rust 的文档,但它似乎有很多我长期以来一直希望用一种语言实现的想法。