2017-07-29 46 views
0

我有了,其他數據之間的結構,獨特的id有沒有什麼方法可以在HashSet中僅通過類型被哈希值進行查找?

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(&Foo { id: 1, other_data: 0 }).unwrap().other_data;

替代方案可能是HashMap其中密鑰包含在struct內。但是,我不能在結構中使用id,在key中使用重複的id

+0

我不知道Rust很好。在基於引用的語言(如Java)出現此問題時,您可以在HashMap條目關鍵字段中使用盒裝密鑰(無論您是否喜歡Java),而在相應的值對象。在像C或Ada這樣允許引用/指向非盒式類型的語言的語言中,您可以將值存儲在任意位置,並將引用存儲在另一個位置。 Afaik Rust系列可以確保第一個解決方案,也可能是第二個解決方案。 – Gene

+0

也許使用一個枚舉{Key(u32),KeyAndData(u32,u32)}並實現hash/eq,這樣你可以通過key進行查詢並獲得keyanddata?這樣你就不必構建你的'Foo'的尾部。無論如何,你沒有說你爲什麼需要這個,因爲你的玩具示例已經可以不加修改地工作了。 – the8472

+0

@Gene您的第一點是有效的(請參閱[如何在密鑰插入HashMap後保留對密鑰的引用?](https://stackoverflow.com/a/32403439/155423)),但您可以'因爲該解決方案不是內存安全的(Rust會告訴你這樣做) - 鍵的地址可以隨着事物的添加/刪除而改變,所以你會有一個懸掛指針。 Rust實際上不夠聰明,不能說盒裝盒也不錯。請參閱[使用項目字段作爲關鍵字的查找表的常用方式](https://stackoverflow.com/q/43695527/155423)瞭解更多信息。 – Shepmaster

回答

4

當您HashSet::get檢查出的簽名,你會注意到它比你想象的稍微複雜些:

fn get<Q: ?Sized>(&self, value: &Q) -> Option<&T> 
where 
    T: Borrow<Q>, 
    Q: Hash + Eq, 

這樣做是正是爲您解決問題get接受可以從集合中的類型(T: Borrow<Q>)中借用的任何類型的參考(&Q)。應該將「T」理解爲「我的類型」,Q應該理解爲「查詢類型」。

因此,你需要實現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); 
} 

參見:

相關問題