2017-03-18 9 views
1

特定の入力に対して既知の値を含むHashMapを作成しようとしています。この入力は、特定の特性を実装している限り、複数の型を受け入れることができます。しかし、この場合、特定のタイプのみが与えられ、Rustは好きではありません。錆構造体はHashMapの形質を置き換えることができません

構造体を「形質」に変換する方法はありますか?そうでなければこの問題を修正しますか?

#![allow(unused)] 

use std::collections::HashMap; 
use std::hash::*; 


trait Element: Eq + PartialEq + Hash {} 

trait Reaction<T: Element> {} 


#[derive(Eq, Hash, PartialEq)] 
struct Ion { 
    charge: u16 
} 

impl Element for Ion {} 


#[derive(Eq, Hash, PartialEq)] 
struct RedoxReaction<T: Element> { left: T } 

impl<T: Element> Reaction<T> for RedoxReaction<T> {} 


fn get_sep_database<T: Element>() -> HashMap<RedoxReaction<T>, f32> { 
    let mut map: HashMap<RedoxReaction<T>, f32> = HashMap::new(); 

    let reaction = RedoxReaction { 
     left: Ion { 
      charge: 1 
     } 
    }; 

    // note: expected type `RedoxReaction<T>` 
    //  found type `RedoxReaction<Ion>` 
    map.insert(reaction, 0.000 as f32); 

    return map; 
} 


fn main() { 
    let db = get_sep_database(); 

    let reaction = RedoxReaction { 
     left: Ion { 
      charge: 1 
     } 
    }; 

    // expected this to be 0.000 
    let sep = db.get(&reaction); 
} 

答えて

2

この問題の標準溶液は形質がの代わりに、ジェネリックをオブジェクトを使用することです。 PartialEqEqHashでもないがobject safeであるため、ここでは動作しないこと、しかし

#[derive(Eq, Hash, PartialEq)] 
struct RedoxReaction { left: Box<Element> } 

:具体的には、RedoxReactionは以下のように定義されるだろう。実際には、一方がIonでもう一方がPhotonである場合には、2つのElementsが等しいかどうかを尋ねるのは大変意味がありません。

あなたの要素にenumを使用することをお勧めします。すべての要素が同じ型(enum Element)を持ち、オブジェクトの安全性は問題にはなりません。

+0

あなたの答えをありがとう。しかし、あなたが推測しているように、実行時に新しい 'Element's(この場合は' Molecule's)を作成したいと思います。 enumで可能なのかどうかはわかりません。今のところ、私は自分のコードをどのように変更できるかを見ていきます。 – Charlie

+0

これは次のようになります: 'Element'特性を実装した各構造体に対して、代わりに' Element'列挙型にバリアントを追加します。 Rustでは実行時に型を作成することはできません。また、実行時に列挙型を作成することもできません。そのため、型のファミリの代わりに列挙型を使用しても問題はありません。 –

0

私は最終的には、以下の機能を持つHashMapのキーとしてReactionハッシュを使用することによって、この問題を解決:

use std::collections::hash_map::DefaultHasher; 
use std::hash::*; 

fn reaction_to_hash<E: Element>(reaction: &Reaction<E>) -> u64 { 
    let mut s = DefaultHasher::new(); 
    reaction.hash(&mut s); 
    s.finish() 
} 

次にあなたが値を格納するためにmap.insert(reaction_to_hash(&reaction), <value>)を使用することができ、かつmap.get(& reaction_to_hash(&reaction))を取得するために、値。

関連する問題