%内用规则
#[macro_export]
macro_rules! foo {
(@as_expr $e:expr) => {$e};
($($tts:tt)*) => {
foo!(@as_expr $($tts)*)
};
}
#
# fn main() {
# assert_eq!(foo!(42), 42);
# }
宏并不参与标准的条目可见性与查找流程,因此,如果一个公共可见宏在其内部调用了其它宏,那么被调用的宏也将必须公共可见。这会污染全局命名空间,甚至会与来自其它crate
的宏发生冲突。那些想对宏进行选择性导入的用户也会因之感到困惑;他们必须导入所有宏——包括公开文档并未记录的——才能使代码正常运转。
将这些本不该公共可见的宏封装进需要被导出的宏内部,是一个不错的解决方案。上例展示了如何将常用的as_expr!
宏移至另一个宏的内部,仅有后者公共可见。
之所以用@
,是因为在Rust 1.2下,该标记尚无任何在前缀位置的用法;因此,我们的语法定义不会与任何东西撞车。想用的话,别的符号或特有前缀都可以;但@
的用例已被传播开来,因此,使用它可能更容易帮助读者理解你的代码。
注意:标记
@
先前曾作为前缀被用于表示被垃圾回收了的指针,那时的语言还在采用各种记号代表指针类型。现在的标记@
只有一种用法:将名称绑定至模式中。而在此用法中它是中缀运算符,与我们的上述用例并不冲突。
还有一点,内用规则通常应排在“真正的”规则之前。这样做可避免macro_rules!
错把内规调用解析成别的东西,比如表达式。
如果导出内用规则无法避免(比如说,有一干效用性的宏规则,很多应被导出的宏都同时需要用到它们),你仍可以采用此规则,将所有内用规则封装到一个“究极”效用宏里去:
macro_rules! crate_name_util {
(@as_expr $e:expr) => {$e};
(@as_item $i:item) => {$i};
(@count_tts) => {0usize};
// ...
}
当前内容版权归 DaseinPhaos 或其关联方所有,如需对内容或内容相关联开源项目进行关注与资助,请访问 DaseinPhaos .