2017-07-04 114 views
3

我要代表在類似下面的存儲器中的數據表:有沒有辦法通過枚舉在Rust中索引數組?

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

有一組已知的人,他們每個人擁有一些貨幣。

而且我有以下枚舉:

enum Person { 
    John, 
    Tom, 
    Nick 
} 

enum Currency { 
    USD, 
    EUR 
} 

我想這個編碼數據作爲二維數組,這將是很酷,以便能夠索引的數組元素不被usizeenum。例如:

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

是否可以在Rust中使用數組和枚舉?或者是否有任何其他數據結構可用於此?

我知道HashMap,但它不正是我想要的,因爲:在堆上

  • HashMap作品(什麼使得它遠遠超過普通堆棧中分配陣列慢)

  • HashMap給我不保證該項目存在。例如。每次我想得到一些東西,我不得不解開它,並處理None的情況下,與正常的數組的使用相比,不太方便。

這是How do I match enum values with an integer?不同,因爲我不感興趣,轉換枚舉usize;我只是想通過枚舉訪問數組/地圖項目。

+0

你爲什麼不使用人與貨幣的特質並在John,Tom,Nick和USD,EUR?上實施這些特徵? – Boiethios

+0

聽起來好像你想要一個從名稱 - 貨幣對的關聯數組到一個值。你嘗試過什麼嗎?一個'HashMap'? –

+0

>爲什麼你不使用Person和Currency作爲特質,並在John,Tom,Nick和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]); 
} 

輸出:

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在堆上工作(它比常規堆棧分配數組慢得多) - HashMap不保證該項存在。例如。每次我想'得到'我必須解開它並處理'None'的情況下,與普通數組相比,這是不太方便的。 –

+0

@SergeyPotapov因此,正如在另一個答案中所說的,你必須實現你自己的類型。 – Boiethios

3

如果您需要此使用陣列來實現,這是沒有那麼簡單,因爲它看起來。

爲了能夠在數組中包含這兩條信息(以便能夠通過它們進行索引),首先需要將它們合併到一個類型中,例如,在一個結構:

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 
    } 
} 

然後你可以索引TablePersonCurrency對:

table[(Tom, EUR)] 

Rust playground link to the whole code

+0

謝謝!實現'std :: ops :: Index'是有道理的,我一直在尋找類似於這個的特質。 –

相關問題