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

m1m5dgzv  于 2023-02-16  发布在  其他
关注(0)|答案(3)|浏览(129)

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

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

0tdrvxhp1#

两件事都处理好

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

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

我们已经将主实现移到了需要逗号结尾的版本,然后添加了第二个子句,匹配缺少逗号的大小写,并将其重写到带有逗号的版本。

使逗号可选

DK.指出了另一种选择,使后面的逗号本身是可选的。
这避免了从一个实现委托到另一个实现的需要。

生 rust 1.32

你可以使用?宏repeater来写这个,并且不允许多个尾随逗号:

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

先前版本

这允许多个尾随逗号:

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

esyap4oy2#

换一条线

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

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

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

wfauudbj

wfauudbj3#

另一种选择(如果你使用的是Incremental TT Muncher)是使用一个可选的捕获分隔符+剩余的标记。

macro_rules! example {

    ($name:ident = $value:expr $(, $($tts:tt)*)?) => {
        println!("{} = {}", stringify!($name), $value);
        example!($($($tts)*)?);
    };

    ($value:expr $(, $($tts:tt)*)?) => {
        println!("{}", $value);
        example!($($($tts)*)?);
    };

    () => {};

}

然后可以调用此宏,例如:

example! { A = 1, "B", C = 3, "D" }

并且尾部逗号可以被包括或省略。

相关问题