/*
更多请看:
http://blog.hubwiz.com/2020/01/30/rust-macro/
https://github.com/rooat/RustLearn/blob/master/src/appendix-04-macros.md
https://rustcc.gitbooks.io/rustprimer/content/macro/macro.html
https://rust-by-example.budshome.com/macros.html
定义:Rust宏让你可以发明自己的语法,编写出可以自行展开的代码,也就是我们通常所说的元编程,你甚至可以用Rust宏来创作自己的DSL。
从根本上来说,宏是一种为写其他代码而写代码的方式,即所谓的元编程
运作机制:首先匹配宏规则中定义的模式,然后将匹配 结果绑定到变量,最后展开变量替换后的代码。
调用方式:另外从形式上看,与函数调用的另一个区别是参数可以用圆括号(())、花括号({})、方括号([])中的任意一种括起来,
比如这行也可以写成 println!["Hello, world!"] 或 println!{"Hello, world!"},不过对于 Rust 内置的宏都有约定俗成的括号,
比如 vec! 用方括号,assert_eq! 用圆括号
宏的分类:
声明式宏( declarative macro )来进行元编程(metaprogramming)
过程式宏( procedural macro )来自定义 derive traits
() => {}看起来很神秘,因为它不是标准的rust语法,是macro_rules! 这个宏自己发明的,用来表示一条宏规则,=>左边是匹配模式,右边是 等待展开的代码
rust 有哪些自带宏?
源文件 std/src/macros.rs
panic print println eprint eprintln dbg assert_approx_eq debug_assert debug_assert_eq debug_assert_ne matches r#try write writeln unreachable unimplemented todo compile_error format_args format_args_nl env option_env concat_idents concat line column file stringify include_str include_bytes
module_path cfg include assert asm llvm_asm global_asm log_syntax trace_macros
源文件 alloc/src/macros.rs
vec format
Rust自带的声明宏:
常用的宏函数:assert, cfg, dbg, env, format, eprintln, println, panic, vec。
-------------------------------------------------------------------------------
宏导入导出用 #[macro_use] 和 #[macro_export]。父模块中定义的宏对其下的子模块是可见的,要想子模块中定义的宏在其后面的父模块中可用,需要使用 #[macro_use]。
*/
use std::collections::HashMap;
//-----------------------通用元编程的声明式宏 macro_rules!-------------------------
//一个空的宏
macro_rules! hey{
() => {}
}
//可以定义多条宏规则 感觉就像函数重载
macro_rules! hey2{
() => {};
() => {}
}
//其中name可以更改名字 expr不可更改
macro_rules! yo{
($name:expr) => {
println!("Yo {}!",$name);
}
}
//函数可以打印自己的名字
macro_rules! create_function {
($func_name:ident) => (
fn $func_name() {
println!("function {:?} is called", stringify!($func_name))
}
)
}
//多参数的宏
macro_rules! hey3{
($($name:expr),*) => {}
}
//输入源是成对出现的 =>写法是宏规则定的,不可更改
macro_rules! hey4{
($($key:expr => $value:expr), *) => {{
let mut map = HashMap::new();
$(map.insert($key, $value);) *
map
}}
}
//看一个 vec! 稍微简化的定义
//注意:标准库中实际定义的 vec! 包括预分配适当量的内存。这部分为代码优化,为了让示例简化,此处并没有包含在内。
#[macro_export]
macro_rules! vec {
( $( $x:expr ),* ) => {
{
let mut temp_vec = Vec::new();
$(
temp_vec.push($x);
)*
temp_vec
}
};
}
//-----------------------自定义 derive 的过程式宏-------------------------
extern crate hello_macro;
#[macro_use]
extern crate hello_macro_derive;
use hello_macro::HelloMacro;
#[derive(HelloMacro)]
struct Pancakes;
/*
hello_macro_derive存在的意义:其实我们完全不用hello_macro_derive也可以实现类似功能
然而,他们需要为每一个他们想使用 hello_macro 的类型编写实现的代码块。我们希望为其节约这些工作。
另外,我们也无法为 hello_macro 函数提供一个能够打印实现了该 trait 的类型的名字的默认实现:Rust 没有反射的能力,因此其无法在运行时获取类型名。我们需要一个在运行时生成代码的宏。
extern crate hello_macro;
use hello_macro::HelloMacro;
struct Pancakes;
impl HelloMacro for Pancakes {
fn hello_macro() {
println!("Hello, Macro! My name is Pancakes!");
}
}
*/
fn main() {
//-----------------------通用元编程的声明式宏 macro_rules!-------------------------
hey!();
yo!("666666666666");
yo!["666666666666"];
yo!{"666666666666"};
//yo!<"666666666666">; 前三种写法都是正确的,唯独这个不行
create_function!(foo);
foo();
hey3! ("Finn", "Jake", "PB");
let user = hey4! (
"liujiayu" => 30,
"liuyalin" => 31
);
println!("user {:?}",user);
//-----------------------自定义 derive 的过程式宏-------------------------
Pancakes::hello_macro();
}
/*
-----------------------自定义 derive 的过程式宏依赖-------------------------
本包toml:
[dependencies]
hello_macro = { path = "./hello_macro" }
hello_macro_derive = { path = "./hello_macro/hello_macro_derive" }
------------------------------------------------------------------------------------
hello_macro包lib.rs:
/*
对于一个 foo 的包来说,一个自定义的派生过程式宏的包被称为 foo_derive
*/
pub trait HelloMacro {
fn hello_macro();
}
----------------------------------------------------------------------------------
hello_macro_derive包lib.rs:
extern crate proc_macro;
extern crate syn;
#[macro_use]
extern crate quote;
use proc_macro::TokenStream;
#[proc_macro_derive(HelloMacro)]
pub fn hello_macro_derive(input: TokenStream) -> TokenStream {
// Construct a string representation of the type definition
let s = input.to_string();
// Parse the string representation
let ast = syn::parse_derive_input(&s).unwrap();
// Build the impl
let gen = impl_hello_macro(&ast);
// Return the generated impl
gen.parse().unwrap()
}
fn impl_hello_macro(ast: &syn::DeriveInput) -> quote::Tokens {
let name = &ast.ident;
quote! {
impl HelloMacro for #name {
fn hello_macro() {
println!("impl_hello_macro--->Hello, Macro! My name is {}", stringify!(#name));
}
}
}
}
----------------------------------------------------------------------------------
hello_macro_derive包toml:
[lib]
proc-macro = true
[dependencies]
syn = "0.11.11"
quote = "0.3.15"
*/