有没有办法通过Rust中的枚举索引数组?

时间:2017-07-04 08:28:37

标签: arrays enums hashmap rust

我想在内存中表示一个数据表,如下所示:

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

有一组已知的人,他们每个人都拥有一些货币。

我有以下枚举:

enum Person {
    John,
    Tom,
    Nick
}

enum Currency {
    USD,
    EUR
}

我想将这些数据编码为2D数组,能够索引不是usize而是enum的数组元素会很酷。 E.g:

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

是否可以使用Rust中的数组和枚举?或者是否有任何其他数据结构可用于此?

我知道HashMap,但这并不是我想要的,因为:

  • HashMap在堆上工作(这使得它比常规堆栈分配的数组慢得多)

  • HashMap不保证该项目存在。例如。每次我想得到的东西我都需要解开它并处理None的情况,与普通数组的使用相比,这不是很方便。

这与How do I match enum values with an integer?不同,因为我对将枚举转换为usize不感兴趣;我只想通过枚举方便地访问数组/地图项目。

3 个答案:

答案 0 :(得分:6)

如果你需要使用数组实现它,这并不像看起来那么简单。

为了能够在数组中包含这两条信息(能够通过它们进行索引),首先需要将它们组合在一个类型中,例如:在结构中:

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

然后,您可以使用TablePerson对对Currency编制索引:

table[(Tom, EUR)]

Rust playground link to the whole code

答案 1 :(得分:5)

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 :(得分: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]);
}