Rust的宏系统远比C的预处理器宏强大。它是在AST层面操作的代码生成工具,分为声明宏(macro_rules!)和过程宏(proc macro)。本课深入宏的核心概念和实际应用。
// 简单宏
macro_rules! say_hello {
() => {
println!("Hello from macro! 🦀");
};
}
// 带参数的宏
macro_rules! create_function {
($func_name:ident) => {
fn $func_name() {
println!("函数 {} 被宏创建", stringify!($func_name));
}
};
}
create_function!(foo);
create_function!(bar);
// 可变参数
macro_rules! sum {
($($x:expr),*) => {{
0 $(+ $x)*
}};
}
// 多种匹配模式
macro_rules! command {
(hello) => { println!("你好!") };
(hello $name:expr) => { println!("你好, {}!", $name) };
(add $a:expr, $b:expr) => { println!("{} + {} = {}", $a, $b, $a + $b) };
}
fn main() {
say_hello!();
foo();
bar();
println!("sum: {}", sum!(1, 2, 3, 4, 5));
println!("sum: {}", sum!(10, 20));
command!(hello);
command!(hello "Rust");
command!(add 3, 5);
}
✅ 验证通过
// 片段分类符
// expr → 表达式: 1 + 2, foo()
// ident → 标识符: x, my_func
// ty → 类型: i32, String
// path → 路径: std::collections::HashMap
// stmt → 语句: let x = 5;
// block → 代码块: { ... }
// pat → 模式: Some(x), _
// literal → 字面量: 42, "hello"
// meta → 属性: #[derive(Debug)]
// item → 项: fn foo() {}, struct Bar;
// vis → 可见性: pub, pub(crate)
// tt → token树: 任何token
macro_rules! hashmap {
($($key:expr => $value:expr),*) => {{
let mut map = std::collections::HashMap::new();
$(map.insert($key, $value);)*
map
}};
}
macro_rules! vec_of {
($element:expr; $n:expr) => {{
let mut v = Vec::with_capacity($n);
for _ in 0..$n {
v.push($element);
}
v
}};
}
fn main() {
let scores = hashmap!{
"Alice" => 95,
"Bob" => 87,
"Charlie" => 92
};
println!("成绩: {:?}", scores);
let zeros = vec_of!(0; 5);
println!("零向量: {:?}", zeros);
}
✅ 验证通过
macro_rules! builder {
($name:ident { $($field:ident: $ty:ty),* $(,)? }) => {
pub struct $name {
$(pub $field: $ty,)*
}
impl $name {
pub fn new() -> Self {
$name {
$($field: Default::default(),)*
}
}
$(
pub fn $field(mut self, value: $ty) -> Self {
self.$field = value;
self
}
)*
}
};
}
builder!(ServerConfig {
host: String,
port: u16,
max_connections: usize,
debug: bool,
});
fn main() {
let config = ServerConfig::new()
.host("127.0.0.1".to_string())
.port(8080)
.max_connections(100)
.debug(true);
println!("配置:");
println!(" host: {}", config.host);
println!(" port: {}", config.port);
println!(" max_connections: {}", config.max_connections);
println!(" debug: {}", config.debug);
}
✅ 验证通过
实现自己的print!宏,支持格式化输出。
编写宏自动为枚举实现from_str方法。
// 声明宏: macro_rules! → 简单模式匹配
// 过程宏: proc-macro → AST变换,更强大
// 实用声明宏: 实现单例模式
macro_rules! singleton {
($name:ident: $ty:ty = $init:expr) => {
static $name: std::sync::OnceLock<$ty> = std::sync::OnceLock::new();
fn get_$name() -> &$ty {
$name.get_or_init(|| $init)
}
};
}
singleton!(CONFIG: String = String::from("default"));
fn main() {
println!("配置: {}", get_CONFIG());
// 常用过程宏
println!("过程宏类型:");
println!(" 派生宏: #[derive(Debug, Clone, Serialize)]");
println!(" 属性宏: #[serde(rename_all = "camelCase")]");
println!(" 函数宏: sqlx::query!("SELECT * FROM users")");
}
✅ 验证通过
| 特性 | 宏 | 函数 | 泛型 |
|---|---|---|---|
| 代码生成 | ✅ 编译期展开 | ❌ 运行时调用 | ✅ 单态化 |
| 可变参数 | ✅ | ❌ 固定参数 | ❌ 固定参数 |
| 类型安全 | ⚠️ 模式匹配 | ✅ 编译器检查 | ✅ 编译器检查 |
| 调试难度 | ⚠️ 较难 | ✅ 容易 | ✅ 容易 |
| 编译速度 | ⚠️ 较慢 | ✅ 快 | ✅ 快 |
| 操作语法 | ✅ | ❌ | ❌ |
// 实用宏: 简化测试创建
macro_rules! test_cases {
($func:ident, $( $input:expr => $expected:expr ),*) => {
$(
#[test]
fn concat_idents!(test_, $func, _at, line!())() {
assert_eq!($func($input), $expected);
}
)*
};
}
// 实用宏: 带时间测量
macro_rules! timed {
($label:expr, $block:block) => {{
let start = std::time::Instant::now();
let result = $block;
println!("{}: {:?}", $label, start.elapsed());
result
}};
}
fn main() {
let sum = timed!("1到1亿求和", { (1..=100_000_000u64).sum::() });
println!("结果: {}", sum);
}
✅ 验证通过
// 构建一个简单的HTML DSL
macro_rules! html {
($tag:ident { $($child:tt)* }) => {{
let tag_name = stringify!($tag);
let children = html_inner!($($child)*);
format!("<{}>{}{}>", tag_name, children, tag_name)
}};
($tag:ident $attr:tt { $($child:tt)* }) => {{
let tag_name = stringify!($tag);
let attrs = format_attrs!($attr);
let children = html_inner!($($child)*);
format!("<{} {}>{}{}>", tag_name, attrs, children, tag_name)
}};
}
macro_rules! html_inner {
() => { String::new() };
($text:literal $($rest:tt)*) => {{
let mut s = $text.to_string();
s.push_str(&html_inner!($($rest)*));
s
}};
($tag:ident { $($child:tt)* } $($rest:tt)*) => {{
let mut s = html!($tag { $($child)* });
s.push_str(&html_inner!($($rest)*));
s
}};
}
macro_rules! format_attrs {
({ $($key:ident = $val:literal),* }) => {{
let mut attrs = Vec::new();
$(
attrs.push(format!("{}="{}"", stringify!($key), $val));
)*
attrs.join(" ")
}};
}
fn main() {
// 使用DSL生成HTML
let page = format!(
"Rust DSL {}",
html!{div { "Hello from Rust macro DSL!" }}
);
println!("{}", page);
// 简化版 - 直接构建
let div = format!("{}", "Hello, HTML DSL!");
let p = format!("{}
", "Generated by Rust macros");
println!("{}{}", div, p);
}
Generated by Rust macros
✅ 验证通过
// 查看宏展开
// cargo expand - 展开所有宏
// cargo expand specific_function - 展开特定函数
macro_rules! debug_macro {
($($token:tt)*) => {
println!("tokens: {}", stringify!($($token)*));
};
}
fn main() {
debug_macro!(hello world 1 + 2);
// 常用调试工具
println!("宏调试工具:");
println!(" cargo expand - 查看宏展开结果");
println!(" cargo check - 快速检查语法");
println!(" trybuild crate - 测试过程宏");
println!(" macro_railroad - 可视化宏规则");
// Rust宏的适用场景
println!("适用场景:");
println!(" ✅ DSL(领域特定语言)");
println!(" ✅ 代码生成(derive宏)");
println!(" ✅ 减少样板代码");
println!(" ✅ 编译期计算");
println!(" ❌ 替代函数/泛型的场景");
}
// 模拟ORM字段定义宏
macro_rules! define_model {
($name:ident { $($field:ident: $ty:ty),* $(,)? }) => {
#[derive(Debug, Clone)]
struct $name { $($field: $ty),* }
impl $name {
fn field_names() -> Vec<&'static str> {
vec![$(stringify!($field)),*]
}
fn to_sql_create() -> String {
let fields: Vec = vec![
$(format!("{} TEXT", stringify!($field))),*
];
format!("CREATE TABLE {} ({})", stringify!($name), fields.join(", "))
}
}
};
}
define_model!(User {
id: String,
name: String,
email: String,
});
define_model!(Post {
id: String,
title: String,
content: String,
author_id: String,
});
fn main() {
let user = User { id: "1".into(), name: "Alice".into(), email: "a@b.com".into() };
println!("{:?}", user);
println!("字段: {:?}", User::field_names());
println!("SQL: {}", User::to_sql_create());
let post = Post { id: "1".into(), title: "Hello".into(), content: "World".into(), author_id: "1".into() };
println!("
{:?}", post);
println!("SQL: {}", Post::to_sql_create());
}
✅ 验证通过
fn main() {
println!("Rust宏演进:");
println!(" 2015: macro_rules! 稳定");
println!(" 2019: 过程宏(proc-macro)稳定");
println!(" 2020: 声明宏2.0(macro 2.0)开发中");
println!(" 2024: 更强大的宏模式匹配");
println!();
println!("宏使用统计(crates.io):");
println!(" serde_derive: #1最受依赖");
println!(" derive_more: 常用派生宏扩展");
println!(" thiserror: 错误类型派生");
println!(" builder_derive: Builder模式派生");
println!(" strum: 枚举工具宏");
println!();
println!("宏调试技巧:");
println!(" 1. cargo expand 查看展开结果");
println!(" 2. println!("{}", stringify!(宏参数)) 查看token");
println!(" 3. trybuild测试过程宏编译错误");
println!(" 4. 逐步构建复杂宏,每步验证");
}
Rust的设计哲学贯穿始终:安全、并发、高性能。每个特性都是这三个目标的具体体现。本课所学内容是构建真实Rust应用的基石,务必在实践中反复练习巩固。
记住:Rust的学习曲线虽陡,但一旦掌握,你将获得前所未有的编程信心——编译器就是你的最佳队友。
// 常用标准库宏
fn main() {
// 输出宏
println!("Hello"); // 换行输出
print!("No newline"); // 不换行
eprintln!("Error"); // 标准错误
format!("{}", 42); // 格式化字符串
// 调试宏
dbg!(42); // 打印并返回值
dbg!(2 + 3); // 打印表达式
// 断言宏
assert!(true); // 断言为真
assert_eq!(1 + 1, 2); // 断言相等
assert_ne!(1, 2); // 断言不等
// 选项宏
let opt = Some(5);
if let Some(v) = opt { println!("v={}", v); }
// 编译期宏
println!("文件: {}", file!()); // 当前文件名
println!("行号: {}", line!()); // 当前行号
println!("列号: {}", column!()); // 当前列号
println!("模块: {}", module_path!()); // 模块路径
println!("函数: {}", function_name!());// 函数名
// 其他
todo!("待实现"); // 未实现标记
unimplemented!(); // 未实现
unreachable!(); // 不可达代码
panic!("崩溃"); // 手动panic
// 向量宏
let v = vec![1, 2, 3];
println!("vec: {:?}", v);
// 写入宏
let mut s = String::new();
use std::fmt::Write;
write!(s, "hello").unwrap();
writeln!(s, " world").unwrap();
println!("写入: {}", s);
}