前言#
昨天我们学习了一些比较实用的方法,今天内容比较轻松,简单的了解一下宏2.0的相关内容
宏 2.0#
git link:rfcs#1584- 相关
issue:rust#39412 - 特性:
#![feature(decl_macro)]
注意是声明宏的2.0,官方是有准备想替换掉macro_rules!的,不过还不稳定(未完成),连名字都没决定好,比如macro、decl_macro又或者其它什么的macros-by-example。
所以我们只是简单的了解下即可。
注意:以下内容都是不确定的,将来有可能改变。
语法#
来搞个例子比对下新旧的写法:
#![feature(decl_macro)]
macro_rules! replace_expr_ {
($_t:tt $sub:expr) => { $sub }
}
macro replace_expr($_t:tt $sub:expr) {
$sub
}
macro_rules! count_tts_ {
() => { 0 };
($odd:tt $($a:tt $b:tt)*) => { (count_tts!($($a)*) << 1) | 1 };
($($a:tt $even:tt)*) => { count_tts!($($a)*) << 1 };
}
macro count_tts {
() => { 0 },
($odd:tt $($a:tt $b:tt)*) => { (count_tts!($($a)*) << 1) | 1 },
($($a:tt $even:tt)*) => { count_tts!($($a)*) << 1 },
}他俩几乎长得一模一样,除了两点:
- 看第二组
count_tts的比对,我们使用了关键字macro替代了原本的macro_rules! - 另外规则的结尾我们使用的是
,而不是;,这比较符合我们的认知。
然后我们再看下第一组replace_expr的比对,可以看到除了关键字之外,写法有比较大的区别,2.0中更接近是函数的写法,也是比较符合我们的认知的。当然也不是说一定要这么写,如果你还是习惯旧的写法,也可以写。
至于宏的调用和旧版的以及函数宏一样,宏名字接!,然后再接输入的内容。
宏是规范的条目(macro are proper items)#
和macro_rules宏不同的是,2.0没有文本作用域以及不需要#[macro_export](以及潜在的(potentially)的重新导出),因为macro宏天然表现像是一个符合规范的rust项。
因此,我们可以对它使用可见性限定符,比如pub、pub(crate)、pub(in path)等。
卫生#
这一部分算是改动最大的部分。和macro_rule宏混合式卫生性( mixed site hygiene)限制不同,macro宏具有定义卫生性(definition site hygiene),这意味着macro宏不会泄露(leak)标识符到它调用的外部。
来看个比对例子:
#![feature(decl_macro)]
// try uncommenting the following line, and commenting out the line right after
macro_rules! foo {
// macro foo {
($name: ident) => {
pub struct $name;
impl $name {
pub fn new() -> $name {
$name
}
}
}
}
foo!(Foo);
fn main() {
// this fails with a `macro`, but succeeds with a `macro_rules`
let foo = Foo::new();
}macro_rules!的写法在这种情况下是可行的,但是macro不可行,因为它内部的标识符不会暴露到外部。
当然,后续还是有可能支持某种方式下允许暴露到外部的情况。
总结#
今天我们简单的了解了下声明宏2.0的一些特性。
