proc-macro-workshop:builder-1

godme發表於2022-06-26
  1. 申明宏
    申明宏主要是macro_rules!所定義的符合rust語法的詞法替換工具。
    常用的有format!println!等等
  2. 過程宏
    過程宏相較於申明宏,不僅是類別更多,更多應用場景,也更為複雜,你甚至可以自定義額外語法。
    • 派生宏:常用的使用derive進行標記的宏,rust自動提供的諸如Debug,Eq等。
    • 屬性宏:和派生宏#[derive(XXX)]相似,但是整體結構為#[...]內部資訊都可以自定義,比如#[sorted]
    • 函式式宏:函式式宏使用方法和申明宏相似seq!,但是功能天差地別,你甚至可以自定義語法,而申明宏不能。(如果你不在申明宏中呼叫過程宏的話)。

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中開啟一個用例即可。
每個用例中有相關的提示。

// 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 協議》,轉載必須註明作者和本文連結