在宏中匹配下划线而不是ident

hel*_*ios 1 macros rust rust-macros

我正在创建一个匹配两个表达式和一个标识符的宏.如果不需要,我希望能够忽略标识符,但是如果我_在那里使用,编译器似乎会抱怨.

我的宏:

macro_rules! if_some {
    ($x:expr, $id:ident, $expr:expr) => {
        match $x {
            None => None,
            Some($id) => Some($expr),
        }
    };
}
Run Code Online (Sandbox Code Playgroud)

我想做什么:

if_some!(obtain_an_option(), x, do_something_with(x))
Run Code Online (Sandbox Code Playgroud)

if_some!(obtain_an_option(), _, do_something())
Run Code Online (Sandbox Code Playgroud)

第二次通话失败.

我通过定义第二个if_some_!没有接收到标识符的宏来解决它(我也不能使用第二个模式).我确定有办法说"这里接受一个标识符或只是_.

也许已经有一个宏/功能(就像Option::map现在我想的那样)......不过现在它很好.

DK.*_*DK. 5

最简单的方法是添加与下划线匹配的第二个臂:

macro_rules! if_some {
    ($x:expr, _, $expr:expr) => {
        match $x {
            None => None,
            Some(_) => Some($expr),
        }
    };

    ($x:expr, $id:ident, $expr:expr) => {
        match $x {
            None => None,
            Some($id) => Some($expr),
        }
    };
}
Run Code Online (Sandbox Code Playgroud)

而且,是的,这听起来像你只是想要Option::map.


Mas*_*ara 5

Option::map似乎是这个特定问题的最佳解决方案,但是当您确实需要一个既需要 ident 又需要_作为模式的宏时,您也可以使用$p:pat片段。该片段当然接受更广泛的模式,例如(ref x, y),但通常这是可以接受的。

macro_rules! if_some {
    ($x:expr, $p:pat, $expr:expr) => {
        match $x {
            None => None,
            Some($p) => Some($expr),
        }
    };
}

fn main() {
    println!("{:?}", if_some!(Some(12), x, x + 1)); // Some(13)
    println!("{:?}", if_some!(Some(12), _, 1)); // Some(1)
}
Run Code Online (Sandbox Code Playgroud)