如何在宏中允许可选的尾随逗号?

use*_*932 17 macros rust

这是我想要的合成例子:

macro_rules! define_enum {
    ($Name:ident { $($Variant:ident),* }) => {
        pub enum $Name {
            None,
            $($Variant),*,
        }
    }
}

define_enum!(Foo { A, B });
Run Code Online (Sandbox Code Playgroud)

此代码编译,但如果添加逗号:

define_enum!(Foo { A, B, });
//                     ^
Run Code Online (Sandbox Code Playgroud)

编译失败.我可以解决它:

($Name:ident { $($Variant:ident,)* })
//                             ^
Run Code Online (Sandbox Code Playgroud)

但后来define_enum!(Foo { A, B });失败了,

我应该如何编写一个宏来处理这两种情况:

define_enum!(Foo { A, B });
define_enum!(Foo { A, B, });
Run Code Online (Sandbox Code Playgroud)

She*_*ter 28

处理这两个案件

您可以通过......处理这两种情况来处理这两种情况:

macro_rules! define_enum {
    ($Name:ident { $($Variant:ident,)* }) => {
        pub enum $Name {
            None,
            $($Variant),*,
        }
    };
    ($Name:ident { $($Variant:ident),* }) => {
        define_enum!($Name { $($Variant,)* });
    };
}

define_enum!(Foo1 { A, B });
define_enum!(Foo2 { A, B, });

fn main() {}
Run Code Online (Sandbox Code Playgroud)

我们已将主要实现移动到期望尾随逗号的版本.然后,我们添加了第二个子句,将该案例与缺少的逗号匹配,并使用逗号将其重写为版本.

使逗号可选

DK.指出一个替代方案,使尾随逗号本身是可选的:

($Name:ident { $($Variant:ident),* $(,)* }) => { 
//                                 ^^^^^
Run Code Online (Sandbox Code Playgroud)

这避免了从一个实现委托给另一个实现的需要.

在Rust 2018中,从Rust 1.32开始,您可以使用?宏转发器以更明显的方式编写它,并禁止多个尾随逗号:

($Name:ident { $($Variant:ident),* $(,)? }) => { 
//                                 ^^^^^
Run Code Online (Sandbox Code Playgroud)

  • @DK.我已经编辑了它,但我仍然主张你自己添加一个答案(我会从这个中编辑它).除了我们中的任何一个获得魔术互联网积分之外,投票还允许那些来到这个问题的人选择哪个答案更好*用于他们的用途,这有助于后来的人知道什么是更惯用的解决方案. (7认同)
  • 当您可以在宏模式中的右大括号之前使用 `$(,)*` 时,为什么要费心呢?一个规则,适用于尾随逗号...s。好的,所以它 * 有点 * 超出规范,但极大地减少了重复。 (5认同)
  • @DK。主要原因是因为我没有意识到你可以做到;-)听起来对我来说是一个完美的回答;请添加! (2认同)
  • 您应该知道第二个和第三个解决方案可以匹配一个或多个逗号。`define_enum!(Foo1 { , });` (2认同)

Ald*_*Lau 12

换线

($Name:ident { $($Variant:ident),* }) => {
Run Code Online (Sandbox Code Playgroud)

($Name:ident { $($Variant:ident),* $(,)? }) => {
Run Code Online (Sandbox Code Playgroud)

在末尾添加一个可选的逗号。这适用于稳定的 Rust / 2018 版。此语法也适用于其他分隔符,如分号。