2017-07-04 26 views
3

私は、次のようなメモリ内のデータのテーブルを表現したい:Rustのenumで配列をインデックスする方法はありますか?

 | USD | EUR | 
-----+-----+-----+ 
John | 100 | 50 | 
-----+-----+-----+ 
Tom | 300 | 200 | 
-----+-----+-----+ 
Nick | 200 | 0 | 
-----+-----+-----+ 

人の既知のセットがあり、それらのそれぞれは、いくつかの通貨を所有しています。

そして、私は、次の列挙型を持っている:

enum Person { 
    John, 
    Tom, 
    Nick 
} 

enum Currency { 
    USD, 
    EUR 
} 

私は2次元配列として、このデータをエンコードしたいのですが、ないusizeではなくenumによってインデックス配列要素にできることはクールになります。例:

data[Person::John][Currency::USD] = 100; 

Rustで配列や列挙型を使用することはできますか?または、これに役立つ他のデータ構造がありますか?

私はHashMapの承知していますが、それは私が欲しいものを正確ではないので:

  • HashMapができます(通常のスタックに割り当てられた配列よりも、それははるかに遅い作るもの)ヒープ上

    • HashMap作品私はその商品が存在することを保証しません。例えば。私が何かを取得したいときはいつも、それをアンラップしてNoneのケースを処理しなければならないが、通常の配列の使用法と比べてそれほど便利ではない。

    私はusizeに列挙型を変換するのに興味がないので、これはHow do I match enum values with an integer?は異なっています。私は列挙型で配列/マップ項目にアクセスする便利な方法がほしいです。

  • +0

    John、Tom、Nick、USD、EURでこれらの特性を実装しますか? – Boiethios

    +0

    名前 - 通貨ペアから値への連想配列が必要なようです。何か試しましたか? 'HashMap'ですか? –

    +0

    > PersonとCurrencyをTraitとして使用して、John、Tom、Nick、USD、EURのこれらの特性を実装しないのはなぜですか? 私はこの考えを持っているかどうかはわかりませんが、とにかく私はUSDとEURの列挙型を必要とし、アプリケーションの別の場所で列挙型を必要とします。 >名前と通貨のペアから値への連想配列が必要なようです。何か試しましたか? 返信いただきありがとうございます。私はHashMapを認識していますが、それは私が必要とするものではありません。 HashMapはヒープで動作します。 –

    答えて

    4

    ljedrzは良好な解を提供した。 問題に近づくもう一つの方法は、既存のクレートenum-mapを使用することです。

    あなたCargo.tomlに以下を追加します。

    [dependencies] 
    enum-map = "*" 
    enum-map-derive = "*" 
    

    その後、src/main.rsに:

    extern crate enum_map; 
    #[macro_use] extern crate enum_map_derive; 
    
    #[derive(Debug, EnumMap)] 
    enum Person { John, Tom, Nick } 
    
    #[derive(Debug, EnumMap)] 
    enum Currency { USD, EUR } 
    
    use enum_map::EnumMap; 
    use Person::*; 
    use Currency::*; 
    
    fn main() { 
        // Create 2D EnumMap populated with f64::default(), which is 0.0 
        let mut table : EnumMap<Person, EnumMap<Currency, f64>> = EnumMap::default(); 
    
        table[John][EUR] = 15.25; 
    
        println!("table = {:?}", table); 
        println!("table[John][EUR] = {:?}", table[John][EUR]); 
    } 
    

    出力:

    あなたが形質としてPersonと通貨を使用していないのはなぜ
    table = EnumMap { array: [EnumMap { array: [0, 15.25] }, EnumMap { array: [0, 0] }, EnumMap { array: [0, 0] }] } 
    table[John][EUR] = 15.25 
    
    2

    あなたはHashMapをしたい:

    use std::collections::HashMap; 
    
    #[derive(PartialEq, Eq, Hash)] 
    enum Person { 
        John, 
        Tom, 
        Nick 
    } 
    
    #[derive(PartialEq, Eq, Hash)] 
    enum Currency { 
        USD, 
        EUR 
    } 
    
    type Table = HashMap<Person, HashMap<Currency, f32>>; 
    
    fn main() { 
        let mut table = Table::new(); 
        let mut currency = HashMap::<Currency, f32>::new(); 
    
        currency.insert(Currency::USD, 100_f32); 
        table.insert(Person::John, currency); 
    
        println!("{}", table[&Person::John][&Currency::USD]); 
    } 
    
    +0

    こんにちは、返信いただきありがとうございます。 - HashMapはヒープ上で動作します(通常のスタック割り当て配列よりもはるかに遅いもの) - HashMapは、その項目が存在する保証はありません。例えば。私が何かを取得したいときはいつも、それをアンラップして 'None' caseを処理しなければなりません。通常の配列と比べてそれほど便利ではありません。 –

    +0

    @ SergeyPotapovしたがって、他の答えで述べたように、独自の型を実装する必要があります。 – Boiethios

    3

    使用すると、配列を使用して実装するために、これを必要とする場合、これはそれが見えるかもしれないほど簡単ではありません。

    これらの情報を両方とも配列に含めることができるようにするには、まずそれらを1つのタイプ(例:

    struct Money([(Currency, usize); 2]); 
    
    struct PersonFinances { 
        person: Person, 
        money: Money 
    } 
    

    あなたがテーブルのインデックスにできるようにしたい場合はその後、あなたはそれのためにIndex形質を実装できるように、独自のタイプでそれをラップする必要があります:構造体の

    use std::ops::Index; 
    
    struct Table([PersonFinances; 3]); 
    
    impl Index<(Person, Currency)> for Table { 
        type Output = usize; 
    
        fn index(&self, idx: (Person, Currency)) -> &Self::Output { 
         &self 
         .0 
         .iter() 
         .find(|&pf| pf.person == idx.0) // find the given Person 
         .expect("given Person not found!") 
         .money 
         .0 
         .iter() 
         .find(|&m| m.0 == idx.1) // find the given Currency 
         .expect("given Currency not found!") 
         .1 
        } 
    } 
    

    その後することができますインデックスPersonCurrencyペアによってTable

    table[(Tom, EUR)] 
    

    Rust playground link to the whole code

    +0

    ありがとう! 'std :: ops :: Index'を実装することは理にかなっています。私はこのような特性を探していました。 –

    関連する問題