强曰为道
与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

Rust 系统编程语言完全教程 / 第23章:宏系统

第23章:宏系统

23.1 宏概述

类型关键字说明用途
声明宏macro_rules!模式匹配的宏代码复用
derive 宏#[derive(...)]自动实现 trait派生实现
属性宏#[my_attr]自定义属性代码生成
函数式宏my_macro!(...)过程宏DSL、代码生成

23.2 声明宏(macro_rules!)

基本语法

// 定义一个简单的宏
macro_rules! say_hello {
    () => {
        println!("Hello, macro!");
    };
}

// 带参数的宏
macro_rules! create_function {
    ($func_name:ident) => {
        fn $func_name() {
            println!("调用了函数: {}", stringify!($func_name));
        }
    };
}

fn main() {
    say_hello!();

    create_function!(foo);
    create_function!(bar);
    foo();
    bar();
}

匹配器模式

macro_rules! calculate {
    // 匹配 add(a, b)
    (add $a:expr, $b:expr) => {
        $a + $b
    };
    // 匹配 mul(a, b)
    (mul $a:expr, $b:expr) => {
        $a * $b
    };
    // 匹配多个表达式
    (sum $($x:expr),+ $(,)?) => {
        {
            let mut total = 0;
            $(total += $x;)+
            total
        }
    };
}

fn main() {
    println!("add: {}", calculate!(add 2, 3));       // 5
    println!("mul: {}", calculate!(mul 4, 5));       // 20
    println!("sum: {}", calculate!(sum 1, 2, 3, 4)); // 10
}

常用片段说明符

说明符匹配示例
$x:expr表达式1 + 2, vec![1]
$x:ty类型i32, Vec<String>
$x:ident标识符foo, my_var
$x:pat模式_, Some(x)
$x:stmt语句let x = 1;
$x:block代码块{ ... }
$x:itemfn, struct, impl
$x:literal字面量42, "hello"
$x:tt单个 token tree任意
$x:meta属性内容derive(Debug)

实用宏示例

// HashMap 字面量宏
macro_rules! map {
    ($($key:expr => $value:expr),* $(,)?) => {
        {
            let mut map = std::collections::HashMap::new();
            $(map.insert($key, $value);)*
            map
        }
    };
}

// 测量执行时间的宏
macro_rules! time_it {
    ($label:expr, $block:block) => {
        {
            let start = std::time::Instant::now();
            let result = $block;
            let elapsed = start.elapsed();
            println!("[{}] 耗时: {:?}", $label, elapsed);
            result
        }
    };
}

// 重复调用宏
macro_rules! repeat {
    ($n:expr, $body:expr) => {
        for _ in 0..$n {
            $body;
        }
    };
}

fn main() {
    let scores = map! {
        "Alice" => 95,
        "Bob" => 87,
        "Charlie" => 92,
    };
    println!("{:?}", scores);

    let sum = time_it!("求和", {
        (1..=1_000_000).sum::<i64>()
    });
    println!("结果: {}", sum);

    repeat!(3, println!("重复执行"));
}

递归宏

macro_rules! count {
    () => (0usize);
    ($head:tt $($tail:tt)*) => (1usize + count!($($tail)*));
}

macro_rules! vec_of_strings {
    ($($s:expr),* $(,)?) => {
        vec![$($s.to_string()),*]
    };
}

fn main() {
    println!("count: {}", count!(a b c d e)); // 5

    let names = vec_of_strings!["Alice", "Bob", "Charlie"];
    println!("{:?}", names);
}

23.3 过程宏(Procedural Macros)

过程宏需要单独的 crate:

# Cargo.toml
[lib]
proc-macro = true

[dependencies]
syn = "2"
quote = "1"
proc-macro2 = "1"

derive 宏

// 在 proc-macro crate 中
use proc_macro::TokenStream;
use quote::quote;
use syn::DeriveInput;

#[proc_macro_derive(HelloMacro)]
pub fn hello_macro_derive(input: TokenStream) -> TokenStream {
    let ast: DeriveInput = syn::parse(input).unwrap();
    let name = &ast.ident;

    let gen = quote! {
        impl HelloMacro for #name {
            fn hello_macro() {
                println!("Hello, I'm {}!", stringify!(#name));
            }
        }
    };

    gen.into()
}
// 使用 derive 宏
trait HelloMacro {
    fn hello_macro();
}

#[derive(HelloMacro)]
struct Pancakes;

fn main() {
    Pancakes::hello_macro(); // Hello, I'm Pancakes!
}

属性宏

// proc-macro crate
#[proc_macro_attribute]
pub fn route(attr: TokenStream, item: TokenStream) -> TokenStream {
    let input: syn::ItemFn = syn::parse(item).unwrap();
    let name = &input.sig.ident;
    let attr_str = attr.to_string();

    let gen = quote! {
        pub fn #name() {
            println!("路由: {}", #attr_str);
            #input
        }
    };

    gen.into()
}

函数式过程宏

#[proc_macro]
pub fn sql(input: TokenStream) -> TokenStream {
    let query = input.to_string();
    let gen = quote! {
        {
            println!("SQL: {}", #query);
            // 在实际项目中,这里会编译时验证 SQL 语法
            #query.to_string()
        }
    };
    gen.into()
}

23.4 常用 derive 宏

来源说明
Debugstd调试格式化
Clonestd深拷贝
Copystd位拷贝
PartialEqstd相等比较
Eqstd完全相等
Hashstd哈希
Defaultstd默认值
Serializeserde序列化
Deserializeserde反序列化
Parserclap命令行解析
Errorthiserror错误类型

23.5 宏调试

cargo expand

# 安装
cargo install cargo-expand

# 展开宏
cargo expand
cargo expand my_module

编译时调试

macro_rules! debug_macro {
    ($($tt:tt)*) => {
        // 打印宏接收到的 token
        compile_error!(concat!("tokens: ", stringify!($($tt)*)));
    };
}

// 使用 trace_macros!(nightly)
// #![feature(trace_macros)]
// trace_macros!(true);

23.6 业务场景示例

Builder 模式的宏

macro_rules! builder {
    (
        $(#[$attr:meta])*
        $vis:vis struct $name:ident {
            $(
                $field_vis:vis $field:ident : $field_type:ty
            ),* $(,)?
        }
    ) => {
        $(#[$attr])*
        $vis struct $name {
            $(pub $field: $field_type,)*
        }

        paste::paste! {
            pub struct [<$name Builder>] {
                $($field: Option<$field_type>,)*
            }

            impl [<$name Builder>] {
                pub fn new() -> Self {
                    Self {
                        $($field: None,)*
                    }
                }

                $(
                    pub fn $field(mut self, value: $field_type) -> Self {
                        self.$field = Some(value);
                        self
                    }
                )*

                pub fn build(self) -> Result<$name, String> {
                    Ok($name {
                        $($field: self.$field.ok_or(
                            concat!(stringify!($field), " 未设置")
                        )?,)*
                    })
                }
            }
        }

        impl $name {
            pub fn builder() -> [<$name Builder>] {
                [<$name Builder>]::new()
            }
        }
    };
}

fn main() {
    // 使用 builder 宏
    // let user = User::builder()
    //     .name("Alice".to_string())
    //     .email("alice@example.com".to_string())
    //     .build()
    //     .unwrap();
    println!("Builder 宏示例");
}

日志宏

macro_rules! log {
    (info, $($arg:tt)*) => {
        println!("[INFO  {}:{}] {}", file!(), line!(), format_args!($($arg)*));
    };
    (warn, $($arg:tt)*) => {
        eprintln!("[WARN  {}:{}] {}", file!(), line!(), format_args!($($arg)*));
    };
    (error, $($arg:tt)*) => {
        eprintln!("[ERROR {}:{}] {}", file!(), line!(), format_args!($($arg)*));
    };
}

fn main() {
    log!(info, "服务器启动在端口 {}", 8080);
    log!(warn, "连接数接近上限: {}/{}", 95, 100);
    log!(error, "数据库连接失败: {}", "超时");
}

23.7 本章小结

要点说明
声明宏macro_rules!,模式匹配
derive 宏自动实现 trait
属性宏自定义属性处理
过程宏需要单独 crate,使用 syn/quote
cargo expand宏展开调试工具

扩展阅读

  1. The Rust Reference - Macros — 宏参考
  2. The Little Book of Rust Macros — 声明宏详解
  3. syn 文档 — 过程宏必备库