有什么方法可以将 match 语句的主体与 Rust 宏相匹配吗?

Phi*_*ord 4 macros rust

我有这样的想法:

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

mymatch! {
    x,
    10 => "Ten",
    n if n < 5 => "Less than 5"
}
Run Code Online (Sandbox Code Playgroud)

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

Pet*_*all 5

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

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

if < 5暂时忽略守卫,你可以匹配以下内容:

my_match! {
    x,
    10 => "Ten",
    _ => "something else"
}
Run Code Online (Sandbox Code Playgroud)

使用以下宏:

macro_rules! my_match {
   ($obj:expr, $($matcher:pat => $result:expr),*) => {
       match $obj {
           $($matcher => $result),*
       }
   }
}
Run Code Online (Sandbox Code Playgroud)

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

完整的宏是:

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

并支持这种用法:

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

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

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