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),)*
_=>错误(“无效操作”),
}
}
}
}
}
操作!{
加上:“+”
减去:“-”
}
这种添加变体的方式非常简单,您不能忘记解析。它也是一种非常干燥的溶液
可以很容易地用其他函数(例如反向翻译)扩展这个构造,这些函数在以后肯定需要,并且不必重复解析字符
我会留下我的答案,但这肯定更好!