「这是我参与11月更文挑战的第 10 天,活动详情查看:2021最后一次更文挑战」
构建过程宏,要在cargo.toml里面设置一些参数,这是必须的。一般来说,过程宏必须是一个库,或者作为工程的子库,不能单独作为一个源文件存在,至少目前不行。
所以在 cargo new [proc-lib] --lib
中一般需要标明:
1 | toml复制代码[lib] |
从分类上,可以分为大致3类:
- proc-macro
- proc-macro-derive
- proc-macro-attribute
大致说一下这几种的形态:
格式
简略过一下这几个宏的格式,在后面会具体讲他们的使用范围:
proc-macro
1 | rust复制代码#[proc_macro] |
可以看出函数式的过程宏只接受一个形参,而且必须是pub的。
proc_macro_derive
1 | rust复制代码#[proc_macro_derive(MyDerive)] |
proc_macro_derive 表明了这是继承宏,还定义了新的继承宏的名字 MyDerive。 熟悉rust编程的,都应该知道有个继承宏,一直用得到,就是 Debug。这是标准库里的,可以帮助调试和显示。
proc_macro_attribute
1 | rust复制代码#[proc_macro_attribute] |
可以看到这里的形参是两个,使用的关键字是 proc_macro_attribute。 关于例子,熟悉python的人应该知道修饰器吧,其实本质就是函数(闭包)可以作为一个对象来返回。 比如我需要一个修饰器来测量一个调用函数的运行时间。
示例
使用代码:
1 | rust复制代码#[handler(blog(::hxl::com))] |
宏代码:
1 | rust复制代码#[proc_macro_attribute] |
cargo check
我们可以在终端中看到:
可以看到目前 attr/item
其实都只是被识别成一个个标志符,没有任何意义,因为要把这些标志符组合有很大的难度。所以需要引入:syn/quote
syn & quote
1 | rust复制代码 |
parse_macro_input!
-> 是将TokenStream
转换为语法树- 当识别成
AttributeArgs
,输出的是Vec<NestedMeta>
- 当识别成
Item
,输出的是Item
- 当识别成
quote!
-> 可以将语法树及其节点转换为TokenStream
#body_ast
并不属于 Rust 表达式,是quote!
自己实现的一种自定义语法- 返回值是
proc_macro2::TokenStream
,通过into()
才能转换,这个有历史原因 quote/syn/proc_macro2
目的都是为了更方便处理和编辑以及生成proc_macro::TokenStream
本文转载自: 掘金