Enums 如何确保在编译时从特定函数返回每个枚举变量?

Enums 如何确保在编译时从特定函数返回每个枚举变量?,enums,rust,Enums,Rust,我有一个枚举: enum操作{ 添加 减去, } impl操作{ fn来自(s:&str)->结果{ 火柴{ “+”=>Ok(Self::Add), “-”=>Ok(Self::Subtract), _=>错误(“无效操作”), } } } 我希望在编译时确保在from函数中处理每个枚举变量 为什么我需要这个?例如,我可能会添加一个Product操作,而忘记在from函数中处理这种情况: enum操作{ // ... 产品,, } impl操作{ fn来自(s:&str)->结果{ //没有变

我有一个枚举:

enum操作{
添加
减去,
}
impl操作{
fn来自(s:&str)->结果{
火柴{
“+”=>Ok(Self::Add),
“-”=>Ok(Self::Subtract),
_=>错误(“无效操作”),
}
}
}
我希望在编译时确保在
from
函数中处理每个枚举变量

为什么我需要这个?例如,我可能会添加一个
Product
操作,而忘记在
from
函数中处理这种情况:

enum操作{
// ...
产品,,
}
impl操作{
fn来自(s:&str)->结果{
//没有变化,我忘了为“产品”添加匹配臂。
火柴{
“+”=>Ok(Self::Add),
“-”=>Ok(Self::Subtract),
_=>错误(“无效操作”),
}
}
}

是否可以保证match表达式返回枚举的每个变量?如果没有,那么模仿这种行为的最佳方法是什么?

虽然使用过程宏检查代码肯定有一种复杂而脆弱的方法,但更好的方法是使用测试。测试更加健壮,编写速度更快,并且将验证每个变量返回的环境,而不仅仅是它出现在某个地方

如果担心在向枚举添加新变量后测试可能会继续通过,则可以使用宏确保测试所有情况:

#[derive(PartialEq, Debug)]
enum Operation {
    Add,
    Subtract,
}

impl Operation {
    fn from(s: &str) -> Result<Self, &str> {
        match s {
            "+" => Ok(Self::Add),
            "-" => Ok(Self::Subtract),
            _ => Err("Invalid operation"),
        }
    }
}

macro_rules! ensure_mapping {
    ($($str: literal => $variant: path),+ $(,)?) => {
        // assert that the given strings produce the expected variants
        $(assert_eq!(Operation::from($str), Ok($variant));)+

        // this generated fn will never be called but will produce a 
        // non-exhaustive pattern error if you've missed a variant
        fn check_all_covered(op: Operation) {
            match op {
                $($variant => {})+
            };
        }
    }
}

#[test]
fn all_variants_are_returned_by_from() {
   ensure_mapping! {
      "+" => Operation::Add,
       "-" => Operation::Subtract,
   }
}
#[派生(PartialEq,调试)]
枚举操作{
添加
减去,
}
impl操作{
fn来自(s:&str)->结果{
火柴{
“+”=>Ok(Self::Add),
“-”=>Ok(Self::Subtract),
_=>错误(“无效操作”),
}
}
}
宏规则!确保映射{
($($str:literal=>$variant:path),+$(,)?)=>{
//断言给定的字符串生成预期的变量
$(assert_eq!(操作::from($str),Ok($variant));)+
//此生成的fn将永远不会被调用,但将生成
//如果您遗漏了变体,则会出现非穷举模式错误
fn检查所有覆盖范围(操作:操作){
匹配操作{
$($变量=>{})+
};
}
}
}
#[测试]
fn所有的变量都由()返回{
确保映射{
“+”=>操作::添加,
“-”=>运算::减法,
}
}

解决方案是使用宏生成整个枚举、变量和转换臂:

macro_rules! operations {
    (
        $($name:ident: $chr:expr)*
    ) => {
        #[derive(Debug)]
        pub enum Operation {
            $($name,)*
        }
        impl Operation {
            fn from(s: &str) -> Result<Self, &str> {
                match s {
                    $($chr => Ok(Self::$name),)*
                    _ => Err("Invalid operation"),
                }
            }
        }
    }
}

operations! {
    Add: "+"
    Subtract: "-"
}
macro\u规则!操作{
(
$($name:ident:$chr:expr)*
) => {
#[导出(调试)]
发布枚举操作{
$($name,)*
}
impl操作{
fn来自(s:&str)->结果{
火柴{
$($chr=>Ok(Self::$name),)*
_=>错误(“无效操作”),
}
}
}
}
}
操作!{
加上:“+”
减去:“-”
}
这种添加变体的方式非常简单,您不能忘记解析。它也是一种非常干燥的溶液

可以很容易地用其他函数(例如反向翻译)扩展这个构造,这些函数在以后肯定需要,并且不必重复解析字符


我会留下我的答案,但这肯定更好!