过程宏

属性宏继承宏函数宏

找了一个19年的文章,不知道代码还能不能跑,但是写的内容合适,看了基本就知道咋回事了 主要突出一个理解概念 https://dengjianping.github.io/2019/02/28/%E5%A6%82%E4%BD%95%E7%BC%96%E5%86%99%E4%B8%80%E4%B8%AA%E8%BF%87%E7%A8%8B%E5%AE%8F(proc-macro).html

属性宏

#[proc_macro_attribute]

pub fn run_time(_: TokenStream, func: TokenStream) -> TokenStream {

let func = parse_macro_input!(func as ItemFn);

let func_vis = &func.vis; // like pub

let func_block = &func.block; // { some statement or expression here }

let func_decl = func.sig;

let func_name = &func.ident; // function name

let func_generics = &func_decl.generics;

let func_inputs = &func_decl.inputs;

let func_output = &func_decl.output;

let caller = quote!{

// rebuild the function, add a func named is_expired to check user login session expire or not.

#func_vis fn #func_name #func_generics(#func_inputs) #func_output {

use std::time;

let start = time::Instant::now();

#func_block

println!("time cost {:?}", start.elapsed());

}

};

caller.into()

}

#[run_time]

fn deco(t: u64) {

let secs = Duration::from_secs(t);

thread::sleep(secs);

}

// ...

deco(6);

这个其实像ts里那个装饰器,看代码 func_vis 这类的从名字和注释能看出来是啥,然后,要做的是修改函数内容,#是把字符串变成真的!这里就会出现在start之后,执行原有的函数内容,也就是那个func_block,然后继续执行println!

继承宏

这个例子是实现了一个打印结构体的功能

#[proc_macro_derive(Show)]

pub fn derive_show(item: TokenStream) -> TokenStream {

// 解析整个token tree

let input = parse_macro_input!(item as DeriveInput);

let struct_name = &input.ident; // 结构体名字

// 提取结构体里的字段

let expanded = match input.data {

Data::Struct(DataStruct{ref fields,..}) => {

if let Fields::Named(ref fields_name) = fields {

// 结构体中可能是多个字段

let get_selfs: Vec<_> = fields_name.named.iter().map(|field| {

let field_name = field.ident.as_ref().unwrap(); // 字段名字

quote! {

&self.#field_name

}

}).collect();

let implemented_show = quote! {

// 下面就是Display trait的定义了

// use std::fmt; // 不要这样import,因为std::fmt是全局的,无法做到卫生性(hygiene)

// 编译器会报错重复import fmt当你多次使用Show之后

impl std::fmt::Display for #struct_name {

fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {

// #(#get_self),*,这是多重匹配,生成的样子大概是这样:&self.a, &self.b, &self.c, ...

// 用法和标准宏有点像,关于多个匹配,可以看这个文档

// https://docs.rs/quote/1.0.0/quote/macro.quote.html

write!(f, "{} {:?}", stringify!(#struct_name), (#(#get_selfs),*))

}

}

};

implemented_show

} else {

panic!("sorry, may it's a complicated struct.");

}

}

_ => panic!("sorry, Show is not implemented for union or enum type.")

};

expanded.into()

}

use your_crate_name::Show;

// ...

#[derive(Show)]

struct MySelf {

name: String,

age: u8,

}

// ...

let me = MySelf{name: "Jamie", age: 255};

println!("{}", me); // MySelf (Jamie, 255)

我们直接看他代码写的啥,他如果是这个 Data::Struct(DataStruct{ref fields,…}),然后就从这个fields里找name,然后是把name收集起来,get_selfs是一个vec,他用来装一下结果,然后在后面为这个结构体实现一个display trait,打印出来get_selfs,返回implemented_show,实现了这个trait后面就可以打印他了

函数宏

#[proc_macro]

pub fn my_proc_macro(ident: TokenStream) -> TokenStream {

let new_func_name = format!("test_{}", ident.to_string());

let concated_ident = Ident::new(&new_func_name, Span::call_site()); // 创建新的ident,函数名

let expanded = quote! {

// 不能直接这样写trait bound,T: Debug

// 会报错,找不到Debug trait,最好给出full path

fn #concated_ident(t: T) {

println!("{:?}", t);

}

};

expanded.into()

}

这个好像就比较素,直接修改函数名字,函数内容啥的

推荐文章

评论可见,请评论后查看内容,谢谢!!!评论后请刷新页面。