proc-macro-workshop:builder-1

基础宏分类#

  1. 申明宏
    申明宏主要是 macro_rules! 所定义的符合 rust 语法的词法替换工具。
    常用的有 format!println! 等等
  2. 过程宏
    过程宏相较于申明宏,不仅是类别更多,更多应用场景,也更为复杂,你甚至可以自定义额外语法。
    • 派生宏:常用的使用 derive 进行标记的宏,rust 自动提供的诸如 Debug,Eq 等。
    • 属性宏:和派生宏#[derive(XXX)] 相似,但是整体结构为#[...] 内部信息都可以自定义,比如#[sorted]
    • 函数式宏:函数式宏使用方法和申明宏相似 seq!,但是功能天差地别,你甚至可以自定义语法,而申明宏不能。(如果你不在申明宏中调用过程宏的话)。

proc-macro-workshop#

proc-macro-workshopdtolnay 大神为菜鸟学习 rust-macro 而创建的教学性质仓库。根据提示不断的进行学习和作答,从而逐渐掌握 rust 宏的编写。

因为常见的 rust 代码、框架中总是充斥着各种各样的宏,总是勾引我的好奇心,分散注意力,因此我觉得有必要先对基本的宏进行学习,只有明白它的实现原理,能基本实现简单的宏,在使用的时候才能做到 “手有余粮,心中不慌” 的坦然境界。

基础工程#

  1. 独立项目:自定义宏一般不能在当前项目中,因为需要提前编译
  2. 基础引入:
    proc-macro-workshop:builder-1
    需要申明使用基础的 proc-macro
  3. 常用的三方库:synquote 都是 dtolany 大佬的作品,这让我们自定义宏的时候更加的方便。
    cargo install cargo-edit cargo-expand

    安装 cargo-edit 以后,我们可以简单的引入第三方依赖 cargo add syn quote
    安装 cargo-expand 以后,我们可以通过 cargo expand 对我们宏作用的代码进行展开,观察它具体的作用效果。

  4. 项目结构说明

proc-macro-workshop:builder-1

可以看到,整体项目为我们准备了难题,依次是

  • 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 协议》,转载必须注明作者和本文链接