proc-macro-workshop:builder-1
基础宏分类
- 申明宏
申明宏主要是macro_rules!
所定义的符合rust
语法的词法替换工具。
常用的有format!
,println!
等等 - 过程宏
过程宏相较于申明宏,不仅是类别更多,更多应用场景,也更为复杂,你甚至可以自定义额外语法。- 派生宏:常用的使用
derive
进行标记的宏,rust
自动提供的诸如Debug
,Eq
等。 - 属性宏:和派生宏
#[derive(XXX)]
相似,但是整体结构为#[...]
内部信息都可以自定义,比如#[sorted]
。 - 函数式宏:函数式宏使用方法和申明宏相似
seq!
,但是功能天差地别,你甚至可以自定义语法,而申明宏不能。(如果你不在申明宏中调用过程宏的话)。
- 派生宏:常用的使用
proc-macro-workshop
proc-macro-workshop是dtolnay
大神为菜鸟学习rust-macro
而创建的教学性质仓库。根据提示不断的进行学习和作答,从而逐渐掌握rust
宏的编写。
因为常见的
rust
代码、框架中总是充斥着各种各样的宏,总是勾引我的好奇心,分散注意力,因此我觉得有必要先对基本的宏进行学习,只有明白它的实现原理,能基本实现简单的宏,在使用的时候才能做到“手有余粮,心中不慌”的坦然境界。
基础工程
- 独立项目:自定义宏一般不能在当前项目中,因为需要提前编译
- 基础引入:
需要申明使用基础的proc-macro
- 常用的三方库:
syn
,quote
都是dtolany
大佬的作品,这让我们自定义宏的时候更加的方便。cargo install cargo-edit cargo-expand
安装
cargo-edit
以后,我们可以简单的引入第三方依赖cargo add syn quote
。
安装cargo-expand
以后,我们可以通过cargo expand
对我们宏作用的代码进行展开,观察它具体的作用效果。 - 项目结构说明
可以看到,整体项目为我们准备了难题,依次是
builder
debug
seq
sorted
bitfield
网上有很多详尽的版本,但是我这里只为应付测试,只做最基础的了解,通过即可。有兴趣的小伙伴可以自行加深,如有受过,还请不吝赐教。
每个项目之下,会有多个测试用例,也就是相当于我们的关卡,完成一关,就在progress.rs
中打开一个用例即可。
每个用例中有相关的提示。
builder-1题解
// This test looks for a derive macro with the right name to exist. For now the
// test doesn't require any specific code to be generated by the macro, so
// returning an empty TokenStream should be sufficient.
//
// Before moving on, have your derive macro parse the macro input as a
// syn::DeriveInput syntax tree.
//
// Spend some time exploring the syn::DeriveInput struct on docs.rs by clicking
// through its fields in the documentation to see whether it matches your
// expectations for what information is available for the macro to work with.
//
//
// Resources:
//
// - The Syn crate for parsing procedural macro input:
// https://github.com/dtolnay/syn
//
// - The DeriveInput syntax tree which represents input of a derive macro:
// https://docs.rs/syn/1.0/syn/struct.DeriveInput.html
//
// - An example of a derive macro implemented using Syn:
// https://github.com/dtolnay/syn/tree/master/examples/heapsize
use derive_builder::Builder;
#[derive(Builder)]
pub struct Command {
executable: String,
args: Vec<String>,
env: Vec<String>,
current_dir: String,
}
fn main() {}
提示中说了,我们不需要做任何操作,只需要returning an empty TokenStream
,但是建议我们先解析一下syn::DeriveInput
和熟悉一下这三个东西
有兴趣的小伙伴可以自行阅读,这里还是以为测试用例为主线,只关注涉及的相关知识。
#[proc_macro_derive(Builder)]
pub fn derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
// 解析一下input as DeriveInput
let _ = syn::parse_macro_input!(input as syn::DeriveInput);
// 返回一下空结果
proc_macro::TokenStream::new()
}
做刚好的问题的解就好,后续每一关,单独拎出来详细讲解,慢慢水下去。
本作品采用《CC 协议》,转载必须注明作者和本文链接