web-dev-qa-db-ja.com

マクロでオプションの末尾のコンマを許可するにはどうすればよいですか?

これが私が欲しいものの合成例です:

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

両方のケースを処理する

両方のケースを処理するには...両方のケースを処理します。

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

メインの実装を、末尾のコンマが必要なバージョンに移動しました。次に、カンマが欠落しているケースに一致する2番目の句を追加し、カンマを使用してバージョンに書き換えます。

カンマをオプションにする

DK。は代替案を指摘しています 、末尾のコンマ自体をオプションにします:

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

これにより、ある実装から別の実装に委任する必要がなくなります。

Rust 2018、Rust 1.32から始まり、?マクロリピーターを使用して、これをより明確な方法で記述し、複数の末尾を禁止することができますカンマ:

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

行を変更します

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

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

末尾にオプションのコンマを追加します。これは安定したRust/2018エディションで機能します。この構文は、セミコロンなどの他の区切り文字でも機能します。

2
RedAldaron