Rust 編程視頻教程(進階)——029

視頻地址

頭條地址:https://www.ixigua.com/i6775861706447913485

源碼地址

講解內容

1、過程宏介紹過程宏接收 Rust 代碼作為輸入,在這些代碼上進行操作,然後產生另一些代碼作為輸出,而非像聲明式宏那樣匹配對應模式然後以另一部分代碼替換當前代碼。定義過程宏的函數接受一個 TokenStream 作為輸入併產生一個 TokenStream 作為輸出。這也就是宏的核心:宏所處理的源代碼組成了輸入 TokenStream,同時宏生成的代碼是輸出 TokenStream。如下:

<code>use proc_macro; 
#[some_attribute]
pub fn some_name(input: TokenStream) -> TokenStream {
}/<code>

2、自定義derive宏(1)mkdir learn_marco2(2)cargo new hello_macro –lib(3)cd hello_macro ,編輯src/lib.rs如下:

<code>pub trait HelloMacro {
fn hello_macro();
}/<code>

(4)cargo new hello_macro_derive –lib(5)編輯hello_macro_derive/Cargo.toml添加如下:

<code>[lib]
proc-macro = true
[dependencies]
syn = "0.14.4"
quote = "0.6.3"/<code>

(6)編輯hello_macro_derive/src/lib.rs如下:

<code>extern crate proc_macro;
use crate::proc_macro::TokenStream;
use quote::quote;
use syn;
#[proc_macro_derive(HelloMacro)]

pub fn hello_macro_derive(input: TokenStream) -> TokenStream {
// 構建 Rust 代碼所代表的語法樹
// 以便可以進行操作
let ast = syn::parse(input).unwrap();//解析出DeriveInput結構體
// 構建 trait 實現
impl_hello_macro(&ast)
}
fn impl_hello_macro(ast: &syn::DeriveInput) -> TokenStream {
let name = &ast.ident;
let gen = quote! {
impl HelloMacro for #name {
fn hello_macro() {
println!("Hello, Macro! My name is {}", stringify!(#name));
}
}
};
gen.into()
}/<code>

(7)使用宏:cd ..(8)cargo new pancakes(9)編輯pancakes/Cargo.toml如下:

<code>[dependencies]
hello_macro = { path = "../hello_macro" }
hello_macro_derive = { path = "../hello_macro/hello_macro_derive" }/<code>

(10)編輯pancakes/src/main.rs如下:

<code>use hello_macro::HelloMacro;
use hello_macro_derive::HelloMacro;
#[derive(HelloMacro)]
struct Pancakes;

fn main() {
Pancakes::hello_macro();
}/<code>

說明:在hello_macro_derive函數的實現中,syn 中的 parse_derive_input 函數獲取一個 TokenStream 並返回一個表示解析出 Rust 代碼的 DeriveInput 結構體(對應代碼syn::parse(input).unwrap();)。該結構體相關的內容大體如下:

<code>DeriveInput { 
// --snip--

ident: Ident {
ident: "Pancakes",
span: #0 bytes(95..103)
},
data: Struct(
DataStruct {
struct_token: Struct,
fields: Unit,
semi_token: Some( Semi )
}
)
}/<code>

3、類屬性宏類屬性宏與自定義派生宏相似,不同於為 derive 屬性生成代碼,它們允許你創建新的屬性。例子:可以創建一個名為 route 的屬性用於註解 web 應用程序框架(web application framework)的函數:

<code>#[route(GET, "/")] fn index() {/<code>

#[route] 屬性將由框架本身定義為一個過程宏。其宏定義的函數簽名看起來像這樣:

<code>#[proc_macro_attribute] pub fn route(attr: TokenStream, item: TokenStream) -> TokenStream {/<code>

說明:類屬性宏其它工作方式和自定義derive宏工作方式一致。

4、類函數宏類函數宏定義看起來像函數調用的宏。類似於 macro_rules!,它們比函數更靈活。例子:如sql!宏,使用方式為:

<code>let sql = sql!(SELECT * FROM posts WHERE id=1);/<code>

則其定義為:

<code>#[proc_macro] pub fn sql(input: TokenStream) -> TokenStream {/<code>

5、宏的資料推薦https://danielkeep.github.io/tlborm/book/mbe-macro-rules.html


分享到:


相關文章: