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

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:item fn, 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 宏

来源 说明
Debug std 调试格式化
Clone std 深拷贝
Copy std 位拷贝
PartialEq std 相等比较
Eq std 完全相等
Hash std 哈希
Default std 默认值
Serialize serde 序列化
Deserialize serde 反序列化
Parser clap 命令行解析
Error thiserror 错误类型

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("[email protected]".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 文档 — 过程宏必备库