2017-03-31 27 views
7

這裏有我想要的東西合成的例子:如何在宏中允許可選的尾隨逗號?

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

回答

11

您可以通過處理這兩種情況處理...兩種情況:

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

我們已將主實現移至exp影響尾隨的逗號。然後,我們添加了第二個子句,使用缺少的逗號匹配案例,並用逗號將其重寫爲版本。


DK. points out an alternative,使得後面的逗號本身可選:

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

這避免了需要委託從一個實現到另一個。

生鏽的夜間版本,你可以使用macro_at_most_once_rep特徵更明顯的方式來寫這一點,並禁止多個後逗號:

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

爲什麼與麻煩時,你可以使用'$(,)* '就在宏觀模式的大括號之前?一條規則,適用於拖曳逗號... s。好吧,這是一個*小*超出規格,但極大地減少了重複。 –

+1

@DK。主要原因是因爲我沒有意識到你可以做到這一點;-)聽起來像對我來說是一個完全córulent的答案;請添加它! – Shepmaster

+0

呃,你在這裏第一,你已經有了四個無意義的互聯網點。更快將其編輯爲您的最佳選擇。 –