enums - 我最接近通过 char 区分枚举的是什么?

标签 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") vs 只是类型转换。

最佳答案

您的字符串是标记值;这是 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,
        }
    }
}

如果您愿意,您也可以为 Mask 实现 std::str::FromStr,这将允许 "A".parse() ==好的(掩码::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],但如果您需要要添加新元素,它会更改类型,如果是公共(public)的,这会破坏 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,
];

关于enums - 我最接近通过 char 区分枚举的是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35283736/

相关文章:

java - Equals 枚举类型中的方法

C# "Enum"序列化 - 反序列化为静态实例

java - Java 中 int 转换为 enum

postgresql - 如何将类似 C 的枚举与柴油一起使用

php - 为什么我没有收到 FCGI_END_REQUEST 记录?

rust - 人类可读的数字

java - (反)序列化枚举集

java - 我可以像 Swift 那样在 Java Enum 中使用函数类型吗?

rust - 如何测试是否调用了回调闭包?

macros - 如何在宏中导入类型?