#pattern #pattern-match #match #variant #enums #macro #duplicates

无std match-commutative

对模式进行交换律匹配,减少重复模式的使用。↔️

3个版本

0.1.0 2023年9月16日
0.1.0-alpha.12023年6月4日

#1927 in Rust模式

MIT/Apache

10KB

match-commutative ↔️

对模式进行交换律匹配,减少重复模式的使用。


Pipeline Status Crates.io version Downloads docs.rs docs


文档

https://docs.rs/match-commutative

动机

当需要匹配三个形成交换律数学关系的值时,通常需要重复很多模式。让我们看看这可能会是什么样子

// imagine that these values come from somewhere and we need to match on them
let operant1 = Operant::Str(Some("42".into()));
let operant2 = Operant::Num(Some(1));
let operator = Operator::Plus;

match (operant1, operator, operant2) {
    (
        Operant::Str(Some(operant_str)),
        Operator::Plus,
        Operant::Num(Some(operant_num)),
    )
    | (
        Operant::Num(Some(operant_num)),
        Operator::Plus,
        Operant::Str(Some(operant_str)),
    ) if operant_str.len() < 3 => {
        let result = operant_num + operant_str.parse::<isize>().unwrap();
        println!("Result is: {}", result);
    }
    (
        Operant::Str(Some(operant_str)),
        Operator::Mult,
        Operant::Num(Some(operant_num)),
    )
    | (
        Operant::Num(Some(operant_num)),
        Operator::Mult,
        Operant::Str(Some(operant_str)),
    ) if operant_str.len() < 3 => {
        let result = operant_num * operant_str.parse::<isize>().unwrap();
        println!("Result is: {}", result);
    }
    (_, _, _) => {
        panic!("Not relevant for this example")
    }
}

// Types that we use in this example
enum Operant {
    Str(Option<String>),
    Num(Option<isize>),
}

enum Operator {
    Plus,
    Mult,
    Minus,
}

对于 Operator::{Plus, Mult},我们必须为每个模式都写两个完全相同的模式(用 | (or-pattern) 连接它们)并执行相同的逻辑。模式中唯一的区别是操作数的顺序。不好!

使用 match-commutative 代替

使用 match-commutative 这可以简化为

use match_commutative::match_commutative;
// imagine that these values come from somewhere and we need to match on them
let operant1 = Operant::Str(Some("42".into()));
let operant2 = Operant::Num(Some(1));
let operator = Operator::Plus;

match_commutative!(
    operant1,
    operator,
    operant2,
    Operant::Str(Some(operant_str)),
    Operator::Plus,
    Operant::Num(Some(operant_num)) if operant_str.len() < 3 => {
        let result = operant_num + operant_str.parse::<isize>().unwrap();
        println!("Result is: {}", result);
    },
    Operant::Str(Some(operant_str)),
    Operator::Mult,
    Operant::Num(Some(operant_num)) if operant_str.len() < 3 => {
        let result = operant_num * operant_str.parse::<isize>().unwrap();
        println!("Result is: {}", result);
    }
    non_commut {
        _, _, _ => {
            // in `non_commut` block, patterns and their execution block behave exactly like std Rust
            panic!("Not relevant for this example")
        }
    }
);

// Types that we use in this example
enum Operant {
    Str(Option<String>),
    Num(Option<isize>),
}

enum Operator {
    Plus,
    Mult,
    Minus,
}

注意,在上面的示例中,operant1operant2 的值可以互换,而仍然产生相同的程序输出。 因此,我们已经成功地在模式中避免了表达 顺序(在两个 Operant 之间不需要顺序)。✨

使用 non_commut 块匹配非交换律操作数

如果您需要匹配非交换律操作数,可以将模式放入可选的 non_commut 块中。在 non_commut 中模式的行为与 std Rust 完全相同

use match_commutative::match_commutative;
let operant1 = Operant::Str(Some("42".into()));
let operant2 = Operant::Num(Some(1));
let operator = Operator::Minus; // a non-commutative operator!

let result = match_commutative!(
        operant2,
        operator,
        operant1,
        Operant::Str(_),
        Operator::Plus,
        Operant::Num(_) => {
            // do something here
            todo!()
        }
        non_commut {
            // for minus operations, we get different results depending on the
            // ordering of the operants
            Operant::Num(Some(op_num)),
            Operator::Minus,
            Operant::Str(Some(op_str)) if op_str.len() < 3 => {
                op_num - op_str.parse::<isize>().unwrap()
            },
            Operant::Str(Some(op_str)),
            Operator::Minus,
            Operant::Num(Some(op_num)) if op_str.len() < 3 => {
                op_str.parse::<isize>().unwrap() - op_num
            },
            _,_,_ => {
                // catch all match arm
                todo!()
            }
        }
    );

assert_eq!(-41, result);

// Types that we use in this example
enum Operant {
    Str(Option<String>),
    Num(Option<isize>),
}

enum Operator {
    Plus,
    Mult,
    Minus,
}

入门

在您的 Cargo.toml 文件中,在 [dependencies] 下添加以下行

match-commutative = "0.1.0"

安全性

该crate使用 100% 安全的Rust 实现,这通过使用 #![forbid(unsafe_code)] 来确保。

MSRV

此crate的最小支持的Rust版本为 1.54。MSRV的增加将通过小版本更改来指示(根据SemVer)。




许可证

许可协议为Apache License, Version 2.0MIT许可协议,您可任选其一。
除非您明确声明,否则您有意提交以包含在本crate中的任何贡献,如Apache-2.0许可协议中定义,将按上述方式双重许可,不附加任何额外条款或条件。

无运行时依赖