17 rust基础 - 宏 macro
📌 Rust 宏(Macro)
Rust 中的 宏(macro) 是一种 元编程 机制,允许编写可扩展、动态生成的代码。相比于函数,宏能够:
- 在编译时展开,减少运行时开销
- 接受不同数量的参数,不像函数必须指定固定的参数
- 操作 Rust 代码结构,可以生成代码块、表达式、类型等
🌟 Rust 宏的四种类型
Rust 提供了 4 种主要的宏:
| 宏类型 | 用途 |
|---|---|
声明式宏(macro_rules!) |
最常用的宏,用于模式匹配、代码展开 |
| 过程宏(Procedural Macros) | 处理 Rust 代码的自定义宏 |
| 派生宏(Derive Macros) | 通过 #[derive] 自动生成 trait 实现 |
| 属性宏(Attribute Macros) | 自定义属性,影响编译行为 |
🟢 1. 声明式宏(macro_rules!)
声明式宏 使用 macro_rules! 定义,类似于 模式匹配,可以匹配不同的参数模式并展开代码。
📌 1.1 例子:最简单的宏
macro_rules! say_hello {
() => {
println!("Hello, Rust macros!");
};
}
fn main() {
say_hello!(); // 调用宏(类似函数,但不用 `()`)
}
📌 1.2 例子:带参数的宏
macro_rules! print_value {
($val:expr) => {
println!("Value: {}", $val);
};
}
fn main() {
print_value!(42);
print_value!("Rust is awesome!");
}
$val:expr:表示参数$val是一个表达式println!()也是一个宏,它接受不同类型的输入
📌 1.3 例子:匹配多个模式
宏可以有多个分支:
macro_rules! my_macro {
() => {
println!("No arguments!");
};
($val:expr) => {
println!("One argument: {}", $val);
};
($a:expr, $b:expr) => {
println!("Two arguments: {}, {}", $a, $b);
};
}
fn main() {
my_macro!();
my_macro!(10);
my_macro!("Hello", 20);
}
🔹 编译器会自动选择匹配的模式。
📌 1.4 例子:重复匹配 ($()*)
可以匹配 可变数量 的参数:
macro_rules! sum {
($($num:expr),*) => {
{
let mut total = 0;
$(total += $num;)*
total
}
};
}
fn main() {
let result = sum!(1, 2, 3, 4, 5);
println!("Sum: {}", result);
}
🔹 $()* 代表 可重复匹配多个参数,然后展开代码。
🟠 2. 过程宏(Procedural Macros)
过程宏 更强大,适用于 代码转换。主要有三种:
- 派生宏(Derive Macros)
- 函数式宏(Function-like Macros)
- 属性宏(Attribute Macros)
📌 2.1 派生宏(#[derive])
派生宏用于自动实现 trait:
use serde::{Serialize, Deserialize};
#[derive(Debug, Serialize, Deserialize)]
struct User {
name: String,
age: u8,
}
fn main() {
let user = User { name: "Alice".to_string(), age: 25 };
println!("{:?}", user);
}
🔹 #[derive(Debug)] 生成 Debug 实现,方便 println!("{:?}") 打印结构体信息。
📌 2.2 自定义过程宏
需要在 独立的 proc-macro crate 里实现:
use proc_macro::TokenStream;
#[proc_macro]
pub fn my_macro(input: TokenStream) -> TokenStream {
println!("Macro input: {}", input);
input
}
🔹 过程宏可以操作 AST(抽象语法树),比 macro_rules! 更灵活。
🔴 3. 宏 VS 函数
| 特点 | 函数 | 宏 |
|---|---|---|
| 代码展开方式 | 运行时调用 | 编译时展开(零成本) |
| 类型检查 | 需要固定参数类型 | 可以适配不同类型 |
| 灵活性 | 只能有固定参数 | 可变参数数量,模式匹配 |
| 语法复杂度 | 简单 | 较难调试 |
🟣 4. 宏的常见问题
❌ 1. 宏定义范围
mod macros {
macro_rules! my_macro {
() => {
println!("Hello from macro!");
};
}
}
fn main() {
my_macro!(); // ❌ 错误:宏 `my_macro!` 在 `mod macros` 里,无法直接使用
}
✅ 解决方法:使用 #[macro_export]
#[macro_export]
macro_rules! my_macro {
() => {
println!("Hello from macro!");
};
}
❌ 2. 传递 tt(Token Tree)
Rust 宏 不能直接传递 if、let 等关键字:
macro_rules! bad_macro {
($keyword:tt) => { // ❌ `tt` 匹配不了 Rust 关键字
$keyword println!("This won't work!");
};
}
fn main() {
bad_macro!(if); // ❌ 编译错误
}
✅ 解决方法:直接传入完整代码块:
macro_rules! good_macro {
($block:block) => {
$block
};
}
fn main() {
good_macro!({
if true {
println!("Now it works!");
}
});
}
🌟 总结
| 概念 | 说明 |
|---|---|
声明式宏(macro_rules!) |
基于 模式匹配 的宏,最常用 |
| 过程宏(Procedural Macros) | 用于 AST 代码转换 |
| 派生宏(Derive Macros) | #[derive(Debug)] 自动生成 trait 实现 |
| 属性宏(Attribute Macros) | #[my_macro] 影响编译 |
| 可变参数宏 | $()* 匹配多个参数 |
tt(Token Tree) |
可以匹配任何 Rust 代码 |
macro_export |
让宏在其他模块可见 |
Rust 宏很强大,但 调试比较困难,一般用于:
- 代码重复性高的场景
- 性能要求极高的代码
- 框架开发(如
serde,tokio)

浙公网安备 33010602011771号