首页 文章

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

提问于
浏览
6

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

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

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

我有以下枚举:

enum Person {
    John,
    Tom,
    Nick
}

enum Currency {
    USD,
    EUR
}

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

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

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

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

  • HashMap 在堆上运行(是什么让它比常规堆栈分配的数组慢得多)

  • HashMap 不能保证项目存在 . 例如 . 每次我想得到的东西,我必须解开它并处理 None 情况,与普通数组的使用相比,什么不是很方便 .

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

3 回答

  • 5

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

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

    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

  • 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

    你想要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]);
    }
    

相关问题