- 申明宏
申明宏主要是macro_rules!
所定義的符合rust
語法的詞法替換工具。
常用的有format!
,println!
等等 - 過程宏
過程宏相較於申明宏,不僅是類別更多,更多應用場景,也更為複雜,你甚至可以自定義額外語法。- 派生宏:常用的使用
derive
進行標記的宏,rust
自動提供的諸如Debug
,Eq
等。 - 屬性宏:和派生宏
#[derive(XXX)]
相似,但是整體結構為#[...]
內部資訊都可以自定義,比如#[sorted]
。 - 函式式宏:函式式宏使用方法和申明宏相似
seq!
,但是功能天差地別,你甚至可以自定義語法,而申明宏不能。(如果你不在申明宏中呼叫過程宏的話)。
- 派生宏:常用的使用
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
中開啟一個用例即可。
每個用例中有相關的提示。
// 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 協議》,轉載必須註明作者和本文連結