---
title: 过程宏 (Procedural Macros)
url: https://doc.liz6.com/rust/08-macro-system/02-procedural-macros
locale: zh
area: rust
tags:
- rust
- 宏系统
date: 2026-06-30
modified: 2026-06-30
description: 过程宏在编译期运行 Rust 代码,接收 TokenStream、输出 TokenStream——derive 宏为 struct/enum 自动生成 impl,attribute 宏修饰任意项,function-like 宏像函数一样调用但处理 token 流。syn 解析 TokenStream 为 AST,qu…
---

# 过程宏 (Procedural Macros)

> 过程宏在编译期运行 Rust 代码,接收 TokenStream、输出 TokenStream——derive 宏为 struct/enum 自动生成 impl,attribute 宏修饰任意项,function-like 宏像函数一样调用但处理 token 流。syn 解析 TokenStream 为 AST,quote 把 AST 转回 TokenStream,cargo expand 查看展开结果——三者是写过程宏的标准工作流。

## 三种过程宏

```rust
// 1. derive: #[derive(MyTrait)] — 为类型自动生成 impl
#[proc_macro_derive(MyTrait)]
pub fn my_derive(input: TokenStream) -> TokenStream { ... }

// 2. attribute: #[my_attr] — 修饰整个 item (fn, struct, impl)
#[proc_macro_attribute]
pub fn my_attr(attr: TokenStream, item: TokenStream) -> TokenStream { ... }

// 3. function-like: my_macro!(...) — 类似 macro_rules! 但用 Rust 函数处理输入
#[proc_macro]
pub fn my_macro(input: TokenStream) -> TokenStream { ... }
```

过程宏是 Rust 代码，运行在编译期接收和产出 `TokenStream`——一个 token 序列。这比 macro_rules! 更灵活——你可以做任意复杂的编译期计算。

## syn + quote: 事实标准

```rust
use proc_macro::TokenStream;
use syn::{parse_macro_input, DeriveInput};
use quote::quote;

#[proc_macro_derive(Hello)]
pub fn hello_derive(input: TokenStream) -> TokenStream {
    let input = parse_macro_input!(input as DeriveInput);   // TokenStream → AST
    let name = input.ident;
    let gen = quote! {
        impl Hello for #name {
            fn hello() { println!("Hello, {}!", stringify!(#name)); }
        }
    };
    gen.into()                                               // 回到 TokenStream
}
```

`syn` 把 `TokenStream` 解析为 AST（类似 Rust 编译器的前端）。`quote!` 把 Rust 代码转回 token stream，支持插值（`#name`）。

## proc-macro crate 的限制

- 必须是单独的 crate（`Cargo.toml`: `[lib] proc-macro = true`）
- 只能导出 proc macro 函数，不能导出普通函数、类型或常量
- 依赖不能是 cycle——proc macro crate 依赖其他 crate 但不能被同一 workspace 的 crate 依赖回

## cargo expand: 展开宏

```bash
cargo install cargo-expand
cargo expand                          # 展开当前 crate 所有宏
cargo expand my_function              # 展开特定函数
```

这是理解宏行为的最快方式——看到编译器实际处理的代码。

## 参考

- **syn**: docs.rs/syn, **quote**: docs.rs/quote
- **cargo-expand**: github.com/dtolnay/cargo-expand

*Keywords: proc macro, derive, syn, quote, TokenStream, cargo expand, attribute macro, function-like macro*
