2017-07-04 95 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'是有道理的,我一直在寻找类似于这个的特质。 –

相关问题