首页 > 解决方案 > 有没有办法将 match 语句的主体与 Rust 宏匹配?

问题描述

我有这样的想法:

macro_rules! mymatch {
   ($obj:ident, ($matcher:tt => $result:tt),*) => {
       match $obj {
           $matcher
       },
   }
}

mymatch! {
    x,
    10 => "Ten",
    n if n < 5 => "Less than 5"
}

我不想重新实现该match声明,但我确实想在两边添加额外的东西。但是,我不知道如何匹配 match 语句的内容。

标签: macrosrust

解决方案


您的语法有一些问题。如果要匹配重复的模式,则需要以 a 开始分组$,如下所示$($matcher:tt => $result:tt),*

接下来,您可能想要匹配的不仅仅是标识符,因为任何表达式都可以匹配,因此将其更改为expr. 左边=>你会想要一个pat(模式),而不是一个tt. 令牌树是通用的,但例如, inn if n < 5将匹配 5 个单独的令牌 - n, if, n, <, 5- 并且您通常只有在没有其他方法工作时才会依赖它。结果也是如此 - 这也应该是一个expr(表达式)。

现在忽略if < 5守卫,您可以匹配以下内容:

my_match! {
    x,
    10 => "Ten",
    _ => "something else"
}

使用以下宏:

macro_rules! my_match {
   ($obj:expr, $($matcher:pat => $result:expr),*) => {
       match $obj {
           $($matcher => $result),*
       }
   }
}

守卫很烦人,因为它们是可选的,但?量词还不稳定。相反,您必须使用*(0 或更多),即使它在技术上会比您需要的更多匹配。

完整的宏是:

macro_rules! my_match {
   ($obj:expr, $($matcher:pat $(if $pred:expr)* => $result:expr),*) => {
       match $obj {
           $($matcher $(if $pred)* => $result),*
       }
   }
}

并支持这种用法:

let x = 7;
let s = my_match! {
    x,
    10 => "Ten",
    n if x < 5 => "Less than 5",
    _ => "something else"
};
println!("s = {:?}", s); // "Something else" 

块也是expr,所以这也是有效的:

my_match! { 
    x,
    10 => "Ten",
    n if x < 5 => { 
        println!("it was {}", n); 
        "Less than 5" 
    },
    _ => "something else"
};

推荐阅读