Rust macro
Rust 宏
Rust 的宏分为两类,一种是声明宏 macro_rules!
,另一种是过程宏 #[...]
.
声明宏 macro_rules!
声明宏是 Rust 中最常用的宏,通过对源码的模式匹配来实现功能。
语法
参考: reference/macro
-
#[macro_export]
导出宏 -
$x:expr
表明模式匹配一个expr
类型的源码块,并用$x
表示它 -
$( ... ),*$
表明匹配括号中的内容 0 次或多次,每个重复的内容直接由,
分隔
例子: vec!
#[macro_export]
macro_rules! vec {
( $( $x:expr ),* ) => {
{
let mut temp_vec = Vec::new();
$(
temp_vec.push($x);
)*
temp_vec
}
};
}
过程宏
过程宏是一个函数,不过它的输入输出类型是词法对象 TokenStream
,由编译器在编译前调用。
crate
由于技术限制,目前过程宏必须分离在一个单独的 crate 中, 这个 crate 是 proc-macro
类型的
Cargo.toml
[lib]
proc-macro = true
derive
宏
derive
宏用来为结构体等创建默认的 trait 实现。
下面的例子创建一个 HelloMacro
trait 的默认实现宏。
-
使用
下面的例子展示了为
struct Pancakes
创建 traitHelloMacro
的默认实现的方法,这个 trait 中只有一个函数hello_macro()
src/main.rs
use hello_macro::HelloMacro; use hello_macro_derive::HelloMacro; #[derive(HelloMacro)] struct Pancakes; fn main() { Pancakes::hello_macro(); }
-
trait 定义
hello_macro/src/lib.rs
pub trait HelloMacro { fn hello_macro(); }
-
宏定义
hello_macro_derive/Cargo.toml
[lib] proc-macro = true [dependencies] syn = "1.0" quote = "1.0"
hello_macro_derive/src/lib.rs
extern crate proc_macro; use proc_macro::TokenStream; use quote::quote; use syn; #[proc_macro_derive(HelloMacro)] pub fn hello_macro_derive(input: TokenStream) -> TokenStream { // Construct a representation of Rust code as a syntax tree // that we can manipulate let ast = syn::parse(input).unwrap(); // Build the trait implementation 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() }
Attribute-like
宏
属性宏可以创建新的属性, 与 derive
宏的区别在于参数多了一个属性 attr
, 也就是括号里面的部分,另一个参数 item
就是与 derive
宏一样的内容了。
Function-like
宏
函数宏可以定义像函数一样调用的宏。可以用来定义 DSL
syn: rust parser
syn 是 rust 代码的 parser,可以将源码字符串 TokenStream
转换成语法树 syn::DeriveInput
。
quote: rust 代码模板
quote 的 quote!
宏可以将 rust 语法数据结构变成 TokenStream
qoute_spanned!
宏可以将重复结构中的一个元素单独操作。
qoute 的宏类似于 macro_rules!
只是把 $
换成 #
评论
Comments powered by Disqus