早些時候又被朋友懟了,產出太慢,今天繼續接上回說到的自定義宏。數據結構
話很少說咱直接開碼,咱們cargo new my_macro
建立一個包。而後修改main.rs
:ide
extern crate my_macro; #[macro_use] extern crate my_macro_derive; use my_macro::MyMacro; #[derive(MyMacro)] struct Coder; fn main() { Corder::my_macro(); }
來來來,咱們康康
上面的代碼,咱們看到了#[macro_use]
的語法,這是一個註解,可使被註解的模塊重的宏應用到當前的做用域。一樣下面的咱們又看到一個註解#[derive(MyMacro)]
,這個則是用來獲得一個hello_macro函數的默認實現,也就是會生成對應的代碼,而後再main裏面嘗試調用這個方法。函數
那麼如今咱們就要定義MyMacro這個trait(相似接口,咱們後面再聊,嚶嚶嚶)了,咱們須要新建一個庫。可使用如下命令cargo new my_macro --lib
,而後編輯生成的lib.rs文件code
pub trait MyMacro { fn my_macro(); }
怎麼樣,看着語法格式是否是就是一個接口;pub是rust中的關鍵字,表示這個trait是公開其餘域能夠訪問的。
有了接口以後咱們就要實現它對應的功能行爲,那麼咱們但願這個接口打印一段話;咱們能夠這樣修改:接口
extern crate my_macro; use my_macro::MyMacro; struct Coder; impl MyMacro for Coder { fn my_macro() { println!("熱點1:P照片是網紅的基本素養"); println!("熱點2:極限挑戰"); println!("熱點1:你們仍是要堅持戴口罩"); } } fn main() { Corder::my_macro(); }
這樣咱們能夠任性的給任何想使用咱們的my_macro的類型實現這個代碼塊啦,這樣能夠節約一部分工做。可是這樣還不行,rust這個小夥子沒有反射這個功能,因此他就沒辦法再運行的時候獲取類型名,咱們剛剛想偷懶的那部分就不行了,因此咱們還須要一個再運行時生產代碼的宏。咱們習慣性的會在名字後面帶上xxx_derive
來代表這是一個自定義的過程式宏包。cargo new my_macro_derive --lib
ci
這兩個lib息息相關,因此再同一個目錄下建立是最好不過的事情,並且必需要同時加入依賴,發佈的時候也得一塊兒發佈。而後咱們須要將 my_macro_derive 聲明爲一個過程式宏的包。同時也須要 syn 和 quote 包中的功能,也須要將其加到依賴中。爲 my_macro_derive 將下面的代碼加入到 Cargo.toml 文件中,
注意是my_macro_derive包的配置喲。作用域
[lib] proc-macro = true [dependencies] syn = "*" quote = "*"
修改完配置咱們須要編輯my_macro_derive的lib.rs文件。字符串
extern crate proc_macro; extern crate syn; #[macro_use] extern crate quote; use proc_macro::TokenStream; #[proc_macro_derive(MyMacro)] pub fn my_macro_derive(input: TokenStream) -> TokenStream { let s = input.to_string(); let ast = syn::parse_derive_input(&s).unwrap(); let gen = impl_hello_macro(&ast); gen.parse().unwrap() }
重頭戲來了,這段代碼可算是有點看頭了。剛剛咱們新加的包是用來幹啥的呢,proc_macro
能夠將 Rust 代碼轉換爲相應的字符串。syn
則將字符串中的Rust代碼解析成爲一個能夠操做的數據結構。quote
則將 syn
解析的數據結構反過來傳入到 Rust 代碼中。知道了這些包的做用以後在看上面的代碼一切就變得清晰和明瞭了。input
函數接受一個輸入轉換爲一個字符串類型的變量,而後這個字符串其實就是表明派生MyMacro
代碼的字符串,而後syn
解析轉換字符串成一個數據結構。這個結構可讓咱們拿到所註解的名字如咱們以前定義的Coder
名字等信息。string
萬事具有,只欠一個在註解類型上面實現咱們剛剛MyMacro
的代碼了。繼續在 my_macro_derive
中編輯lib.rs
:
fn impl_my_macro(ast: &syn::DeriveInput) -> quote::Tokens { let name = &ast.ident; quote! { impl MyMacro for #name { fn my_macro() { println!("你好熱點送上了! 類型名: {}.", stringify!(#name)); } } } }
大功告成。在最初的my_macro包中加入對應的依賴:
[dependencies] hello_macro = { path = "../hello_macro" } hello_macro_derive = { path = "../hello_macro/hello_macro_derive" }
而後執行文章開頭的代碼,cargo run
。就會打印出:你好熱點送上了! 類型名:Corder.
因此接下來就是大家的時間了,好好捋捋上面說的東西吧。(逃