ifs

Macro ifs 

Source
macro_rules! ifs {
    { // * 📝←左边的括号只是标注「推荐用括弧」而对实际解析无限定作用
        $( $guardian:expr => $value:expr $(,)? )* // ! 可选的逗号
    } => { ... };
    {
        $f_guardian:tt => $f_value:tt;
        $( $guardian:expr => $value:expr $(,)? )* // ! 可选的逗号
    } => { ... };
    {
        $( let $pattern:pat = $input:expr => $value:expr $(,)? )* // ! 可选的逗号
    } => { ... };
    {
        $input:expr;
        $( match $pattern:pat => $value:expr $(,)? )* // ! 可选的逗号
    } => { ... };
    ( @VALUE _ $value:expr ) => { ... };
    ( @VALUE (_) $value:expr ) => { ... };
    ( @VALUE ($($f:tt)+) $value:expr ) => { ... };
}
Expand description

§ifs!:依次匹配并执行

  • 🎯用于简写「并列性判断」结构
    • 📌可用于简写连续的if - if - if「并列分支」结构

§用法

§常规用法

use nar_dev_utils::ifs;
fn see(v: &str) {
    ifs! {
        v.is_empty() => println!("空的!"),
        v.starts_with('0') => println!("以零开头!"),
        v.starts_with('1') => println!("以一开头!"),
        v.starts_with('2') => println!("以二开头!"),
        v.len() > 5 => println!("超长字符串!"),
        v.starts_with('3') => println!("以三开头!"),
    }
}

将被转换成

fn see(v: &str) {
    if v.is_empty() {
       println!("空的!")
    }
    if v.starts_with('0') {
        println!("以零开头!")
    }
    if v.starts_with('1') {
        println!("以一开头!")
    }
    if v.starts_with('2') {
        println!("以二开头!")
    }
    if v.len() > 5 {
        println!("超长字符串!")
    }
    if v.starts_with('3') {
        println!("以三开头!")
    }
}

§结合「预处理函数」实现批量应用

use nar_dev_utils::ifs;
use std::fmt::Display;
fn see(v: &str) {
    #[inline(always)]
    fn println<T: Display>(x: T) {
        println!("{}", x)
    }
    ifs! {
        // 格式:`(预处理输入) => (预处理输出)`
        (v.starts_with) => (println);
        '0' => "以零开头!",
        '1' => "以一开头!",
        '2' => "以二开头!",
        '3' => "以三开头!",
        " " => String::from("以空格开头!"), // ! println是直接被平铺到各个调用处的,因此这里能编译成功
    }
}

将被转换并内联成

fn see(v: &str) {
    // 预处理输出展开:输出统一用`println`包裹,并内联成`println!`
    // 预处理输入展开:统一插入`v.starts_with`
    if v.starts_with('0') {
        println!("以零开头!")
    }
    if v.starts_with('1') {
        println!("以一开头!")
    }
    if v.starts_with('2') {
        println!("以二开头!")
    }
    if v.starts_with('3') {
        println!("以三开头!")
    }
}
§可以用 _ 跳过预处理
use nar_dev_utils::ifs;
/// * 🎯debug @ 多余的逗号
fn see_bool(v: bool) {
    ifs! {
        // 格式:`(预处理输入) => (预处理输出)`
        _ => _; // * 🚩相当于原样输出
        v => print!("真!"), // * 🚩只有`v == true`时才进入此分支
       !v => print!("假!"), // 反之
    }
}

§用例

use nar_dev_utils::{ifs, show, asserts};
let v: &str = "1";
// 测试1 不安排「预处理函数」 | 匹配一个无意义的值,使用匹配守卫来确定「唯一进入的分支」
let mut v1 = "这啥玩意…";
ifs! {
    v.is_empty() => v1="空的!",
    v.starts_with('0') => v1="以零开头!",
    v.starts_with('1') => v1="以一开头!",
    v.starts_with('2') => v1="以二开头!",
    v.len() > 5 => v1="超长字符串!",
    v.starts_with('3') => v1="以三开头!",
};
// 测试2 使用「成员方法」预处理被匹配项 | 此时 v == "以一开头!"
let mut v2 = "这啥玩意…";
ifs! {
    (v.starts_with) => (_);
    '0' => v2="以零开头!",
    '1' => v2="以一开头!",
    '2' => v2="以二开头!",
    '3' => v2="以三开头!",
};
// 测试3 多重模式匹配
let mut v3 = "";
ifs! {
    "以一开头!".chars().next().unwrap();
    match '0'..='9' => v3 = "匹配数字!",
    match '以' => v3 = "匹配「以」!",
    match '一' => v3 = "匹配「一」!",
    match '开' => v3 = "匹配「开」!",
    match '头' => v3 = "匹配「头」!",
};
// 测试4 使用「属性」同时处理被匹配项和匹配值
struct F<I, R>(Box<dyn Fn(I) -> R>);
let f = F(Box::new(|c| v2.contains(c))); // 检测的闭包
let f2 = F(Box::new(Box::new)); // 装箱的闭包
let mut v4 = Box::new("这");
let mut clj = |x| v4 = (f2.0)(x);
ifs! {
    (f.0) => (clj);
    '头' => "「头」在里头!",
    '开' => "「开」在里头!",
    '一' => "「一」在里头!",
    '以' => "「以」在里头!",
};
// 展示&断言
asserts! {
    show!(ifs! {@VALUE (1.cmp) &2}) => std::cmp::Ordering::Less
    show!(ifs! {@VALUE (std::any::type_name_of_val) &2}) => "i32"
    show!(v1) => "以一开头!"
    show!(v2) => "以一开头!"
    show!(v3) => "匹配「以」!"
    show!(v4) => Box::new("「以」在里头!")
}