2015-12-11 35 views
6

這僅僅是僞代碼:如何匹配Rust宏中的表達式類型?

macro_rules! attribute { 
    $e: expr<f32> => { /* magical float stuff */ }; 
    $e: expr<i64> => { /* mystical int stuff */ }; 
}; 

我想有根據,我傳遞給宏類型不同擴展的宏。

這是它如何工作在C++

template <typename T> 
struct Attribute{ void operator(T)() {} }; 

template <> 
struct Attribute<float> { 
    void operator(float)(float) { /* magical float stuff */ } 
}; 

template <> 
struct Attribute<long> { 
    void operator()(long) { /* mystical int stuff */ } 
} 
+0

只有宏調度的語法,特點OTOH可以根據類型調度。考慮使用特質,或者在宏內部使用特徵。 – bluss

回答

11

鏽宏都沒有能夠做到這一點。宏在語法層面上運行,而不是在語義層面上運行。這意味着雖然編譯器知道它有一個表達式(語法),但它不知道在宏展開時表達式值(語義)的類型是什麼。

一種解決方法是將預期的類型傳遞給宏:

macro_rules! attribute { 
    ($e:expr, f32) => { /* magical float stuff */ }; 
    ($e:expr, i64) => { /* mystical int stuff */ }; 
} 

fn main() { 
    attribute!(2 + 2, i64); 
} 

,或者更簡單,定義多個宏。


如果要基於表達式的類型進行靜態(編譯時)調度,則可以使用特徵。用必要的方法定義一個特徵,然後實現你需要的特徵。如果impl塊與特徵定義位於同一個包中,則可以實現任意類型的特徵(包括來自其他庫的基元和類型)。

trait Attribute { 
    fn process(&self); 
} 

impl Attribute for f32 { 
    fn process(&self) { /* TODO */ } 
} 

impl Attribute for i64 { 
    fn process(&self) { /* TODO */ } 
} 

macro_rules! attribute { 
    ($e:expr) => { Attribute::process(&$e) }; 
} 

fn main() { 
    attribute!(2 + 2); 
} 

注意:您也可以寫$e.process()宏的身體,但隨後的宏可以稱之爲無關process方法。

+1

所以在這種情況下,生鏽的宏不如C++模板強大? – Arne

+0

@Arne如果這是你想要的方式,那麼肯定。 Rust宏和C++模板在廣泛筆畫中只有可比的,並且具有不同的功能。然而,這兩種*語言*在這裏給你同樣的能力,正如特質例子所證明的那樣。我偏見的觀點是Rust版本更好,因爲你根本不需要模板/宏的元編程 - 我可能會忽略宏,只需調用'(2 + 2).attribute()'在'main'中。 – Shepmaster

+1

@Shepmaster我不需要靜態或動態調度,我需要它在編譯時的結果。 – Arne

1

如前所述,根據expr的類型不能展開不同。但作爲一種變通方法,您可以使用any module,並嘗試從Any性狀垂頭喪氣:

use std::any::Any; 

macro_rules! attribute { 
    ($e:expr) => { 
     if let Some(f) = (&$e as &Any).downcast_ref::<f32>() { 
      println!("`{}` is f32.", f); 
     } else if let Some(f) = (&$e as &Any).downcast_ref::<f64>() { 
      println!("`{}` is f64.", f); 
     } else { 
      println!("I dunno what is `{:?}` :(", $e); 
     } 
    }; 
} 

fn main() { 
    attribute!(0f32); 
    attribute!(0f64); 
    attribute!(0); 
} 

顯示:

`0` is f32. 
`0` is f64. 
I dunno what is `0` :(
相關問題