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

问题描述 投票:15回答:2

这是我想要的合成例子:

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

define_enum!(Foo { A, B });

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

define_enum!(Foo { A, B, });
//                     ^

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

($Name:ident { $($Variant:ident,)* })
//                             ^

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

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

define_enum!(Foo { A, B });
define_enum!(Foo { A, B, });
macros rust
2个回答
25
投票

Handle both cases

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

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() {}

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

Make the comma optional

DK. points out an alternative,使尾随逗号本身可选:

($Name:ident { $($Variant:ident),* $(,)* }) => { 
//                                 ^^^^^

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

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

($Name:ident { $($Variant:ident),* $(,)? }) => { 
//                                 ^^^^^

-1
投票

改变线

($Name:ident { $($Variant:ident),* }) => {

($Name:ident { $($Variant:ident),* $(,)? }) => {

在最后添加一个可选的逗号。这适用于稳定的Rust / 2018版本。此语法也适用于分号等其他分隔符。

© www.soinside.com 2019 - 2024. All rights reserved.