下面是我想要的一个合成示例:

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, });

推荐答案

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,使尾随逗号本身成为可选.

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

rust 1.32

您可以使用?宏中继器写入此命令,并禁止使用多个尾随逗号:

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

以前的版本

这允许使用多个尾随逗号:

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

Rust相关问答推荐

如何从polars DataFrame中获取一个列作为Option String?<>

PyReadonlyArray2到Vec T<>

为什么类型需要在这个代码中手动指定,在rust?

默认特征实现中的生命周期问题

Rust&;Tokio:如何处理更多的信号,而不仅仅是SIGINT,即SIGQUE?

在 Rust 中,在第一个空格上分割字符串一次

Nom 解析器无法消耗无效输入

如何将这些测试放在一个单独的文件中?

不能将 `*self` borrow 为不可变的,因为它也被borrow 为可变的 - 编译器真的需要如此严格吗?

使用 traits 时,borrow 的值不会存在足够长的时间

如何将 Rust 字符串转换为 i8(c_char) 数组?

从现有系列和 map 值创建新系列

我如何将特征作为 struct 的拥有字段?

深度嵌套枚举的清洁匹配臂

Rust 跨同一文件夹中文件的可见性

TinyVec 如何与 Vec 大小相同?

为什么-x试图解析为文字并在声明性宏中失败?

如何用另一个变量向量置换 rust simd 向量?

Rust 中的运行时插件

为什么这里需要类型注解?