2017-05-17 25 views
0

我有一些重複的代碼如何編寫類似匹配武器的宏?

match *x { 
    A(ref a) => "special", 
    B(ref a) => "B foo", 
    C(ref a) => "C foo", 
    D(ref a) => "D foo", 
    // ... 
} 

我想喜歡

macro_rules! generic_fmt { 
    ($T:ident) => { 
     $T(ref a) => {"$T foo"}, 
    } 
} 

所以,我可以簡化我的匹配

match *x { 
    A(ref a) => "special", 
    generic_fmt!(B), 
    generic_fmt!(C), 
    generic_fmt!(D), 
    // ... 
} 

什麼是做到這一點的最好辦法宏?我每晚使用rustc 1.19.0。

回答

2

如果更改輸出一點是可以接受的,你可以使用一個包羅萬象的都是一樣的武器:

match x { 
    Foo::A(ref a) => println!("special"), 
    _ => println!("{:?} Foo", x), 
} 

Playground link

但是這會打印出類型及其參數。如果您每晚都在,並且不怕實驗,則可以使用std::intrinsics::type_name僅顯示類型名稱。

或者您可以使用宏,做你的所有比賽的武器:

macro_rules! gen_match { 
    ($x:ident, $Special:ident, [$($Foo:ident),*]) => { 
     match $x { 
      Foo::$Special(ref a) => println!("special"), 
      $(Foo::$Foo(ref a) => println!("{} foo", stringify!($Foo)),)* 
     } 
    } 
} 

,並調用它:

gen_match!(x, A, [B, C, D]); 

Playground link

周圍的變種,這將是通用格式化括號是爲了可讀性,他們可以從宏定義中刪除

+0

我如何使用'type_name'?它只給了我'Enum'的類型,而不是單個項目? http://play.integer32.com/?gist=b015089c2a81fe44724eea5c4ce006bc&version=undefined – colinfang

+1

哦'type_name'不工作,因爲我雖然'Enum' ...你可以嘗試https://github.com/mockersf/variant-名字,寫起來很有趣 –

1

你不能那麼做。宏不能擴展到match部分(<Variant> => <Expression>)。

,你可以得到的最接近的可能是這樣的:

enum Foo { 
    A(u32), 
    B(u32), 
    C(u32), 
    D(u32), 
} 

macro_rules! gen1 { 
    ($Variant:ident) => { 
     Foo::$Variant(ref a) 
    } 
} 

macro_rules! gen2 { 
    ($Variant:ident) => { 
     concat!(stringify!($Variant), " foo") 
    } 
} 

fn print(x: Foo) { 
    println!("{}", match x { 
     Foo::A(ref a) => "special", 
     gen1!(B) => gen2!(B), 
     gen1!(C) => gen2!(C), 
     gen1!(D) => gen2!(D), 
    }); 
} 

fn main() { 
    print(Foo::A(42)); 
    print(Foo::B(42)); 
    print(Foo::C(42)); 
    print(Foo::D(42)); 
} 

Playground link.