这只是伪代码:
macro_rules! attribute { $e: expr=> { /* magical float stuff */ }; $e: expr => { /* mystical int stuff */ }; };
我希望有一个不同的扩展宏取决于我传递给宏的类型.
这就是它在C++中的工作方式
templatestruct Attribute{ void operator(T)() {} }; template <> struct Attribute { void operator(float)(float) { /* magical float stuff */ } }; template <> struct Attribute { void operator()(long) { /* mystical int stuff */ } }
Francis Gagn.. 20
Rust宏无法做到这一点.宏在语法层面运行,而不是在语义层面运行.这意味着虽然编译器知道它有一个表达式(语法),但它不知道宏扩展时表达式的值(语义)是什么类型.
解决方法是将预期类型传递给宏:
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
方法.
Rust宏无法做到这一点.宏在语法层面运行,而不是在语义层面运行.这意味着虽然编译器知道它有一个表达式(语法),但它不知道宏扩展时表达式的值(语义)是什么类型.
解决方法是将预期类型传递给宏:
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
方法.