Rust尋找挫敗感1.0之宏(下)

早些時候又被朋友懟了,產出太慢,今天繼續接上回說到的自定義宏。數據結構

直接開碼

話很少說咱直接開碼,咱們cargo new my_macro建立一個包。而後修改main.rside

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 --libci

這兩個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.

碼完跑路(偷懶)

因此接下來就是大家的時間了,好好捋捋上面說的東西吧。(逃

相關文章
相關標籤/搜索