我能用char来区分枚举的最接近的是什么?

时间:2016-02-09 04:12:03

标签: enums rust

我已经多次写过这个问题,并且终于意识到我最大的问题是我不知道我想如何表示这些数据,这使得很难推断其余的代码

数据在Python中的表示方式:

class LSP():
    C_MASK_MAP={
        "A":"Ch A",
        "B":"Ch B",
        "C":"Ch C",
        "D":"Ch D",
        "T":"Tmpr",
        "Y":"Batt",
        "L":"Acc"
    }

    ADC_CHANS= (
        "Ch A",
        "Ch B",
        "Ch C",
        "Ch D",
        "Tmpr",
        "Batt"
    )

    ADC_MAJORS = (
        "Ch A",
        "Ch B",
        "Ch C",
    )

我想象中的Rust代码(我知道名称需要更新,但为了清楚起见,这里也是一样的):

enum C_MASK_MAP {
    Ch_A = 'A',
    Ch_B = 'B',
    Ch_C = 'C',
    Ch_D = 'D',
    Tmpr = 'T',
    Batt = 'Y',
    Acc  = 'L'
}
//...
let ADC_CHANS = [
    C_MASK_MAP::Ch_A,
    C_MASK_MAP::Ch_B,
    C_MASK_MAP::Ch_C,
    C_MASK_MAP::Ch_D,
    C_MASK_MAP::Tmpr,
    C_MASK_MAP::Batt
];

ADC_MAJORS = [
    C_MASK_MAP::Ch_A,
    C_MASK_MAP::Ch_B,
    C_MASK_MAP::Ch_C,
];

我考虑过让C_MASK_MAP成为HashMap<char, &'static str>,但后来我遇到了一个巨大的混乱,试图不在任何地方制作一百万份str的副本并处理生命制作String s,以及引用静态str&&'static str或其他东西)的语法混乱。

我认为能够使用枚举(或类似)会有一个真正的好处,因为价值不会那么大,而且更容易互换C_MASK_MAP.get(key).expect("invalid key")而不仅仅是铸造。

2 个答案:

答案 0 :(得分:5)

你的字符串是哨兵值;这是Python中的一种常见模式,但不是Rust应该如何完成的事情:枚举就是这样的事情:你在类型系统中编码合法值。

你最终可能会遇到这样的事情:

#[derive(Clone, Copy)]
#[repr(u8)]
pub enum Mask {
    ChA = b'A',
    ChB = b'B',
    ChC = b'C',
    ChD = b'D',
    Tmpr = b'T',
    Batt = b'Y',
    Acc  = b'L',
}

// e.g. Mask::ChA.into() == 'A'
impl Into<char> for Mask {
    fn into(self) -> char {
        self as u8 as char
    }
}

impl Mask {
    // e.g. Mask::from('A') == Ok(Mask::ChA)
    pub fn from(c: char) -> Result<Mask, ()> {
        match c {
            'A' => Ok(Mask::ChA),
            'B' => Ok(Mask::ChB),
            'C' => Ok(Mask::ChC),
            'D' => Ok(Mask::ChD),
            'T' => Ok(Mask::Tmpr),
            'Y' => Ok(Mask::Batt),
            'L' => Ok(Mask::Acc),
            _ => Err(()),
        }
    }

    // e.g. Mask::ChA.is_chan() == true
    pub fn is_chan(&self) -> bool {
        match *self {
            Mask::ChA | Mask::ChB | Mask::ChC | Mask::ChD | Mask::Tmpr | Mask::Batt => true,
            Mask::Acc => false,
        }
    }

    // e.g. Mask::ChD.is_major() == false
    pub fn is_major(&self) -> bool {
        match *self {
            Mask::ChA | Mask::ChB | Mask::ChC => true,
            Mask::ChD | Mask::Tmpr | Mask::Batt | Mask::Acc => false,
        }
    }
}

如果您愿意,也可以为std::str::FromStr实施Mask,这将允许"A".parse() == Ok(Mask::ChA)

impl FromStr for Mask {
    type Err = ();

    fn from_str(s: &str) -> Result<Mask, ()> {
        match s {
            "A" => Ok(Mask::ChA),
            "B" => Ok(Mask::ChB),
            "C" => Ok(Mask::ChC),
            "D" => Ok(Mask::ChD),
            "T" => Ok(Mask::Tmpr),
            "Y" => Ok(Mask::Batt),
            "L" => Ok(Mask::Acc),
            _ => Err(()),
        }
    }
}

我怀疑is_chan等。可能比ADC_CHANS等更合适,但如果你确实需要它们,它们可以正常工作(你也可以[Mask; 6],但是如果你需要添加新的元素,它会改变类型这是一个API兼容性中断,如果公开):

pub static ADC_CHANS: &'static [Mask] = &[
    Mask::ChA,
    Mask::ChB,
    Mask::ChC,
    Mask::ChD,
    Mask::Tmpr,
    Mask::Batt,
];

pub static ADC_MAJORS: &'static [Mask] = &[
    Mask::ChA,
    Mask::ChB,
    Mask::ChC,
];

答案 1 :(得分:2)

复制&'static str(即仅复制参考)无需任何费用。该字符串的深层副本将是 clone ,并将输入为String

如果&'static str过于冗长,您可以随时定义类型别名。

type Str = &'static str;

HashMap<char, &'static str>很好地与原始地图相对应。但是,如果您不需要密钥的全部范围char,除了索引地图之外,您实际上不需要将值键入为char,应该使用enum,因为这将限制可用作键的合法值。