Rust 精通教程 2:宏编程
宏(Macros)是 Rust 中的元编程工具,允许你在编译时生成代码。Rust 有两种主要的宏类型:声明式宏(declarative macros) 和 过程宏(procedural macros)。今天我们将深入探索 Rust 的宏系统。
1. 声明式宏(macro_rules!)
1.1 基础语法
声明式宏使用 macro_rules! 定义,通过模式匹配来生成代码:
// 一个简单的 vec! 宏实现
macro_rules! my_vec {
// 匹配空参数
() => {
Vec::new()
};
// 匹配单个元素
($elem:expr) => {
{
let mut v = Vec::new();
v.push($elem);
v
}
};
// 匹配多个元素,用逗号分隔
($($elem:expr),+) => {
{
let mut v = Vec::new();
$(
v.push($elem);
)+
v
}
};
// 匹配带尾随逗号的多个元素
($($elem:expr),+ ,) => {
my_vec![$($elem),+]
};
}
fn main() {
let v1 = my_vec![]; // 调用第一个模式
let v2 = my_vec![1]; // 调用第二个模式
let v3 = my_vec![1, 2, 3]; // 调用第三个模式
let v4 = my_vec![1, 2, 3,]; // 调用第四个模式
println!("v2: {:?}", v2);
println!("v3: {:?}", v3);
}
1.2 模式匹配语法
macro_rules! patterns {
// expr: 表达式
(expr $e:expr) => {
println!("表达式: {}", $e);
};
// ty: 类型
(ty $t:ty) => {
let _: $t = Default::default();
println!("类型: {}", stringify!($t));
};
// ident: 标识符
(ident $i:ident) => {
let $i = 42;
println!("标识符 {} 的值: {}", stringify!($i), $i);
};
// stmt: 语句
(stmt $s:stmt) => {
$s
println!("语句执行了");
};
// block: 代码块
(block $b:block) => {
let result = $b;
println!("代码块结果: {}", result);
};
// pat: 模式
(pat $p:pat) => {
match 42 {
$p => println!("模式匹配成功"),
_ => println!("模式匹配失败"),
}
};
// 重复匹配:* 表示0次或多次,+ 表示1次或多次,? 表示0次或1次
(repeat $($item:expr),*) => {
$(
println!("重复项: {}", $item);
)*
};
// 分隔符可以是逗号、分号等
(separator $($key:expr => $value:expr);+) => {
$(
println!("键: {}, 值: {}", $key, $value);
)+
};
}
fn main() {
patterns!(expr 1 + 2);
patterns!(ty String);
patterns!(ident my_var);
patterns!(stmt let x = 10;);
patterns!(block { 20 + 30 });
patterns!(pat 42);
patterns!(repeat 1, 2, 3, 4, 5);
patterns!(separator "one" => 1; "two" => 2; "three" => 3);
}
1.3 递归宏
macro_rules! sum {
// 基本情况
($x:expr) => {
$x
};
// 递归情况:$x + 剩余部分
($x:expr, $($rest:expr),+) => {
$x + sum!($($rest),+)
};
}
macro_rules! json {
// 匹配空对象
({}) => {
std::collections::HashMap::new()
};
// 匹配单个键值对
({ $key:tt : $value:tt }) => {
{
let mut map = std::collections::HashMap::new();
map.insert(
String::from(stringify!($key)),
json_value!($value)
);
map
}
};
// 匹配多个键值对
({ $($key:tt : $value:tt),+ $(,)? }) => {
{
let mut map = std::collections::HashMap::new();
$(
map.insert(
String::from(stringify!($key)),
json_value!($value)
);
)+
map
}
};
}
macro_rules! json_value {
// 字符串
($value:expr) => {
String::from($value)
};
// 数字
($value:literal) => {
format!("{}", $value)
};
// 布尔值
(true) => { String::from("true") };
(false) => { String::from("false") };
// 嵌套对象
({ $($inner:tt)* }) => {
format!("{:?}", json!({ $($inner)* }))
};
// 数组
([ $($elem:tt),* ]) => {
format!("[{:?}]", vec![$(json_value!($elem)),*])
};
}
fn main() {
let total = sum!(1, 2, 3, 4, 5);
println!("总和: {}", total);
// 使用 json! 宏
let data = json!({
name: "Alice",
age: 30,
active: true,
address: {
city: "Beijing",
country: "China"
},
hobbies: ["reading", "swimming"]
});
println!("JSON 数据: {:?}", data);
}
1.4 常见宏示例
// 调试打印宏
macro_rules! debug_print {
($($arg:tt)*) => {
#[cfg(debug_assertions)]
{
println!($($arg)*);
}
};
}
// 断言宏
macro_rules! assert_equal {
($left:expr, $right:expr) => {
assert_eq!($left, $right, "{} 不等于 {}", stringify!($left), stringify!($right));
};
($left:expr, $right:expr, $($arg:tt)+) => {
assert_eq!($left, $right, $($arg)+);
};
}
// 哈希表宏
macro_rules! hashmap {
($($key:expr => $value:expr),* $(,)?) => {
{
let mut map = std::collections::HashMap::new();
$(
map.insert($key, $value);
)*
map
}
};
}
// 枚举变体计数宏
macro_rules! count_variants {
($($variant:ident),* $(,)?) => {
[$(stringify!($variant)),*].len()
};
}
enum Status {
Pending,
Processing,
Completed,
Failed,
}
fn main() {
debug_print!("这条消息只在调试模式下打印");
let x = 10;
let y = 10;
assert_equal!(x, y);
let map = hashmap! {
"one" => 1,
"two" => 2,
"three" => 3,
};
println!("哈希表: {:?}", map);
let count = count_variants!(Pending, Processing, Completed, Failed);
println!("Status 枚举有 {} 个变体", count);
}
2. 过程宏(Procedural Macros)
过程宏有三种类型:
- 派生宏(Derive macros):为结构体/枚举生成代码
- 属性宏(Attribute macros):添加自定义属性
- 函数宏(Function-like macros):类似声明式宏但更强大
2.1 项目设置
过程宏需要单独的 crate:
# Cargo.toml
[package]
name = "my_macros"
version = "0.1.0"
edition = "2021"
[lib]
proc-macro = true
[dependencies]
syn = { version = "2.0", features = ["full"] }
quote = "1.0"
proc-macro2 = "1.0"
2.2 派生宏(Derive Macros)
// src/lib.rs
use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, DeriveInput, Data, Fields};
// 派生宏:自动实现 Hello trait
#[proc_macro_derive(Hello)]
pub fn hello_derive(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
let name = input.ident;
let expanded = quote! {
impl Hello for #name {
fn hello(&self) {
println!("Hello from {}!", stringify!(#name));
}
}
};
TokenStream::from(expanded)
}
// 派生宏:自动实现 ToJson
#[proc_macro_derive(ToJson)]
pub fn to_json_derive(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
let name = input.ident;
let fields = match input.data {
Data::Struct(data) => match data.fields {
Fields::Named(fields) => fields.named,
_ => panic!("只支持命名字段的结构体"),
},
_ => panic!("只支持结构体"),
};
let field_names: Vec<_> = fields.iter()
.map(|f| f.ident.as_ref().unwrap())
.collect();
let field_strings: Vec<_> = field_names.iter()
.map(|name| name.to_string())
.collect();
let expanded = quote! {
impl ToJson for #name {
fn to_json(&self) -> String {
let mut parts = vec![];
#(
parts.push(format!("\"{}\": \"{}\"", #field_strings, self.#field_names));
)*
format!("{{{}}}", parts.join(", "))
}
}
};
TokenStream::from(expanded)
}
2.3 使用派生宏
// src/main.rs
use my_macros::{Hello, ToJson};
trait Hello {
fn hello(&self);
}
trait ToJson {
fn to_json(&self) -> String;
}
#[derive(Hello, ToJson)]
struct Person {
name: String,
age: u32,
city: String,
}
#[derive(Hello)]
struct Dog {
name: String,
breed: String,
}
fn main() {
let person = Person {
name: "Alice".to_string(),
age: 30,
city: "Beijing".to_string(),
};
person.hello();
println!("JSON: {}", person.to_json());
let dog = Dog {
name: "Rusty".to_string(),
breed: "Husky".to_string(),
};
dog.hello();
}
2.4 属性宏(Attribute Macros)
// src/lib.rs
use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, ItemFn};
// 属性宏:记录函数执行时间
#[proc_macro_attribute]
pub fn time_function(args: TokenStream, input: TokenStream) -> TokenStream {
let _args = parse_macro_input!(args as syn::AttributeArgs);
let input = parse_macro_input!(input as ItemFn);
let fn_name = &input.sig.ident;
let fn_block = &input.block;
let fn_vis = &input.vis;
let fn_sig = &input.sig;
let expanded = quote! {
#fn_vis #fn_sig {
let start = std::time::Instant::now();
let result = #fn_block;
println!("函数 {} 执行时间: {:?}", stringify!(#fn_name), start.elapsed());
result
}
};
TokenStream::from(expanded)
}
// 属性宏:添加日志
#[proc_macro_attribute]
pub fn log_function(args: TokenStream, input: TokenStream) -> TokenStream {
let args = parse_macro_input!(args as syn::AttributeArgs);
let input = parse_macro_input!(input as ItemFn);
let fn_name = &input.sig.ident;
let fn_block = &input.block;
let fn_vis = &input.vis;
let fn_sig = &input.sig;
// 解析日志级别
let level = if args.is_empty() {
"INFO".to_string()
} else {
args[0].to_string()
};
let expanded = quote! {
#fn_vis #fn_sig {
println!("[{}] 调用函数: {}", #level, stringify!(#fn_name));
let result = #fn_block;
println!("[{}] 函数 {} 返回: {:?}", #level, stringify!(#fn_name), result);
result
}
};
TokenStream::from(expanded)
}
2.5 使用属性宏
// src/main.rs
use my_macros::{time_function, log_function};
#[time_function]
fn slow_function() -> i32 {
let mut sum = 0;
for i in 0..1_000_000 {
sum += i;
}
sum
}
#[log_function(DEBUG)]
fn divide(a: i32, b: i32) -> Result<i32, String> {
if b == 0 {
Err("除数不能为0".to_string())
} else {
Ok(a / b)
}
}
#[log_function]
fn greet(name: &str) -> String {
format!("Hello, {}!", name)
}
fn main() {
let result = slow_function();
println!("结果: {}\n", result);
match divide(10, 2) {
Ok(r) => println!("除法结果: {}\n", r),
Err(e) => println!("错误: {}\n", e),
}
let greeting = greet("World");
println!("{}", greeting);
}
2.6 函数宏(Function-like Macros)
// src/lib.rs
use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, parse_quote, Expr, Lit};
// 函数宏:SQL 查询构建器
#[proc_macro]
pub fn sql(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as syn::LitStr);
let query = input.value();
// 简单的 SQL 验证
if !query.to_uppercase().starts_with("SELECT") {
panic!("只支持 SELECT 查询");
}
let expanded = quote! {
{
let query = #query;
println!("执行 SQL: {}", query);
// 这里可以添加 SQL 解析和验证逻辑
query.to_string()
}
};
TokenStream::from(expanded)
}
// 函数宏:创建枚举的字符串表示
#[proc_macro]
pub fn enum_strings(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as syn::ItemEnum);
let enum_name = &input.ident;
let variants = &input.variants;
let variant_names: Vec<_> = variants.iter()
.map(|v| &v.ident)
.collect();
let variant_strings: Vec<_> = variant_names.iter()
.map(|name| name.to_string())
.collect();
let expanded = quote! {
impl #enum_name {
pub fn as_str(&self) -> &'static str {
match self {
#(
#enum_name::#variant_names => #variant_strings,
)*
}
}
pub fn from_str(s: &str) -> Option<Self> {
match s {
#(
#variant_strings => Some(#enum_name::#variant_names),
)*
_ => None,
}
}
pub fn all_variants() -> &'static [&'static str] {
&[#(#variant_strings),*]
}
}
};
TokenStream::from(expanded)
}
2.7 使用函数宏
// src/main.rs
use my_macros::{sql, enum_strings};
// 使用 enum_strings 宏
#[enum_strings]
enum Color {
Red,
Green,
Blue,
Yellow,
}
// 手动实现示例
#[derive(Debug)]
enum Status {
Active,
Inactive,
Pending,
}
fn main() {
// 使用 sql 宏
let query = sql!("SELECT * FROM users WHERE id = 1");
println!("查询字符串: {}\n", query);
// 使用自动生成的枚举方法
let color = Color::Red;
println!("Color: {:?}", color);
println!("as_str: {}", color.as_str());
if let Some(c) = Color::from_str("Green") {
println!("from_str: {:?}\n", c);
}
println!("所有变体: {:?}", Color::all_variants());
// 对比手动实现的枚举
let status = Status::Active;
println!("Status: {:?}", status);
}
3. 高级宏技巧
3.1 条件编译宏
macro_rules! conditional {
// 条件为真
(if $cond:expr => $then:expr) => {
if $cond { $then }
};
// 条件为真,否则其他
(if $cond:expr => $then:expr, else $else:expr) => {
if $cond { $then } else { $else }
};
// 多条件
(if $cond:expr => $then:expr, elif $($rest:tt)*) => {
if $cond { $then } else { conditional!($($rest)*) }
};
}
macro_rules! os_specific {
(windows => $windows:expr) => {
#[cfg(target_os = "windows")]
{ $windows }
};
(unix => $unix:expr) => {
#[cfg(any(target_os = "linux", target_os = "macos"))]
{ $unix }
};
(windows => $windows:expr, unix => $unix:expr) => {
#[cfg(target_os = "windows")]
{ $windows }
#[cfg(any(target_os = "linux", target_os = "macos"))]
{ $unix }
};
}
fn main() {
let x = 10;
let result = conditional!(
if x > 5 => "大于5",
elif x > 0 => "大于0",
else "小于等于0"
);
println!("条件结果: {}", result);
// 操作系统特定代码
os_specific!(
windows => println!("这是 Windows 系统"),
unix => println!("这是 Unix 系统")
);
}
3.2 重复模式高级用法
macro_rules! generate_struct {
// 生成结构体
(struct $name:ident {
$($field:ident: $ty:ty),* $(,)?
}) => {
struct $name {
$(
$field: $ty,
)*
}
impl $name {
fn new($($field: $ty),*) -> Self {
Self {
$(
$field,
)*
}
}
fn debug(&self) {
$(
println!("{}: {:?}", stringify!($field), self.$field);
)*
}
}
};
// 生成枚举
(enum $name:ident {
$($variant:ident($($ty:ty),*)),* $(,)?
}) => {
enum $name {
$(
$variant($($ty),*),
)*
}
impl $name {
fn debug(&self) {
match self {
$(
$name::$variant($($args),*) => {
println!("{}: {:?}", stringify!($variant), ($($args),*));
}
)*
}
}
}
};
}
generate_struct! {
struct Person {
name: String,
age: u32,
active: bool
}
}
generate_struct! {
struct Point {
x: f64,
y: f64
}
}
generate_enum! {
enum Shape {
Circle(f64),
Rectangle(f64, f64),
Triangle(f64, f64, f64)
}
}
fn main() {
let person = Person::new(
String::from("Alice"),
30,
true
);
person.debug();
println!();
let point = Point::new(10.5, 20.5);
point.debug();
println!();
let circle = Shape::Circle(5.0);
let rect = Shape::Rectangle(10.0, 20.0);
circle.debug();
rect.debug();
}
3.3 卫生宏与变量捕获
macro_rules! create_fn {
($name:ident, $body:expr) => {
fn $name() {
println!("调用函数: {}", stringify!($name));
let result = $body;
println!("结果: {}", result);
}
};
}
macro_rules! capture_var {
// 注意:宏不会捕获外部变量
($x:ident) => {
println!("捕获的变量: {}", $x);
};
}
macro_rules! with_hygiene {
// 使用 $crate 避免命名冲突
() => {
let x = 42; // 这个 x 是卫生的,不会影响外部
println!("内部 x: {}", x);
};
// 使用特殊的标识符避免冲突
(using $name:ident) => {
let $name = 100;
println!("指定的变量: {}", $name);
};
}
fn main() {
// 创建函数
create_fn!(add_one, {
let x = 10;
x + 1
});
add_one();
// 变量捕获演示
let x = 5;
capture_var!(x); // 可以捕获
// 卫生宏
let x = 10;
println!("外部 x: {}", x);
with_hygiene!();
println!("外部 x 仍然是: {}", x); // 不受影响
with_hygiene!(using y);
println!("外部 y: {}", y); // y 在这里可用
}
4. 实际项目示例:ORM 框架
创建一个简单的 ORM 框架,展示宏的实际应用:
// src/lib.rs (proc-macro crate)
use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, DeriveInput, Data, Fields, Type};
// 派生宏:Model - 为结构体生成数据库操作方法
#[proc_macro_derive(Model, attributes(table, column))]
pub fn model_derive(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
let name = input.ident;
// 获取表名
let table_name = get_table_name(&input.attrs)
.unwrap_or_else(|| name.to_string().to_lowercase());
// 获取字段信息
let fields = match input.data {
Data::Struct(data) => match data.fields {
Fields::Named(fields) => fields.named,
_ => panic!("Model 只支持命名字段的结构体"),
},
_ => panic!("Model 只支持结构体"),
};
let field_names: Vec<_> = fields.iter()
.map(|f| f.ident.as_ref().unwrap())
.collect();
let field_types: Vec<_> = fields.iter()
.map(|f| &f.ty)
.collect();
// 获取列名
let column_names: Vec<String> = fields.iter()
.map(|f| {
get_column_name(&f.attrs)
.unwrap_or_else(|| f.ident.as_ref().unwrap().to_string())
})
.collect();
let primary_key = get_primary_key(&fields);
let expanded = quote! {
impl #name {
// 表名
fn table_name() -> &'static str {
#table_name
}
// 列名
fn column_names() -> Vec<&'static str> {
vec![#(#column_names),*]
}
// 插入语句
fn insert_sql(&self) -> String {
format!(
"INSERT INTO {} ({}) VALUES ({})",
Self::table_name(),
Self::column_names().join(", "),
(0..Self::column_names().len())
.map(|_| "?")
.collect::<Vec<_>>()
.join(", ")
)
}
// 查询语句
fn find_by_id_sql(id: impl ToString) -> String {
format!(
"SELECT * FROM {} WHERE {} = {}",
Self::table_name(),
#primary_key,
id.to_string()
)
}
// 转换为值向量
fn to_values(&self) -> Vec<String> {
vec![
#(
format!("{:?}", self.#field_names)
),*
]
}
}
impl std::fmt::Debug for #name {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct(stringify!(#name))
#(
.field(stringify!(#field_names), &self.#field_names)
)*
.finish()
}
}
};
TokenStream::from(expanded)
}
// 辅助函数:获取表名
fn get_table_name(attrs: &[syn::Attribute]) -> Option<String> {
for attr in attrs {
if attr.path().is_ident("table") {
if let Ok(list) = attr.parse_args::<syn::LitStr>() {
return Some(list.value());
}
}
}
None
}
// 辅助函数:获取列名
fn get_column_name(attrs: &[syn::Attribute]) -> Option<String> {
for attr in attrs {
if attr.path().is_ident("column") {
if let Ok(list) = attr.parse_args::<syn::LitStr>() {
return Some(list.value());
}
}
}
None
}
// 辅助函数:获取主键
fn get_primary_key(fields: &syn::punctuated::Punctuated<syn::Field, syn::token::Comma>) -> String {
for field in fields {
for attr in &field.attrs {
if attr.path().is_ident("column") {
if let Ok(list) = attr.parse_args::<syn::LitStr>() {
if list.value() == "id" {
return list.value();
}
}
}
}
}
// 默认主键
if let Some(field) = fields.iter().find(|f| {
f.ident.as_ref().map_or(false, |id| id == "id")
}) {
"id".to_string()
} else {
fields[0].ident.as_ref().unwrap().to_string()
}
}
4.1 使用 ORM 宏
// src/main.rs
use my_macros::Model;
// 使用派生宏
#[derive(Model)]
#[table("users")]
struct User {
#[column("id")]
id: u32,
name: String,
#[column("email_address")]
email: String,
age: u32,
active: bool,
}
#[derive(Model)]
struct Product {
id: u32,
name: String,
price: f64,
in_stock: bool,
}
// 模拟数据库连接
struct Database;
impl Database {
fn execute(&self, sql: &str, params: Vec<String>) -> Result<(), String> {
println!("执行 SQL: {}", sql);
println!("参数: {:?}", params);
println!("查询成功\n");
Ok(())
}
fn query(&self, sql: &str) -> Result<Vec<Vec<String>>, String> {
println!("执行 SQL: {}", sql);
println!("返回模拟数据\n");
Ok(vec![])
}
}
fn main() {
let db = Database;
// 创建用户
let user = User {
id: 1,
name: "Alice".to_string(),
email: "alice@example.com".to_string(),
age: 30,
active: true,
};
println!("用户数据: {:?}", user);
println!("表名: {}", User::table_name());
println!("列名: {:?}", User::column_names());
println!("插入 SQL: {}", user.insert_sql());
println!("查询 SQL: {}", User::find_by_id_sql(1));
println!("值: {:?}\n", user.to_values());
// 执行插入
db.execute(&user.insert_sql(), user.to_values()).unwrap();
// 创建产品
let product = Product {
id: 100,
name: "Rust Book".to_string(),
price: 49.99,
in_stock: true,
};
println!("产品数据: {:?}", product);
println!("表名: {}", Product::table_name());
println!("列名: {:?}", Product::column_names());
println!("插入 SQL: {}", product.insert_sql());
println!("值: {:?}", product.to_values());
}
5. 调试和测试宏
5.1 调试宏展开
// 使用 stringify! 调试
macro_rules! debug_macro {
($($tokens:tt)*) => {
{
println!("宏输入: {}", stringify!($($tokens)*));
$($tokens)*
}
};
}
// 使用 log_syntax!(需要 nightly)
#![feature(log_syntax)]
macro_rules! trace_macro {
($($tokens:tt)*) => {
{
log_syntax!($($tokens)*);
$($tokens)*
}
};
}
// 测试宏
fn main() {
let x = debug_macro!(1 + 2 * 3);
println!("结果: {}", x);
// 查看宏展开
// 在命令行使用: cargo rustc -- -Z unstable-options --pretty=expanded
}
5.2 测试宏
#[cfg(test)]
mod tests {
// 测试 vec! 宏
#[test]
fn test_vec_macro() {
let v = vec![1, 2, 3];
assert_eq!(v, [1, 2, 3]);
}
// 测试自定义宏
macro_rules! add {
($a:expr, $b:expr) => {
$a + $b
};
}
#[test]
fn test_add_macro() {
assert_eq!(add!(2, 3), 5);
assert_eq!(add!(10, 20), 30);
}
// 测试带重复的宏
macro_rules! sum {
($($x:expr),*) => {
{
let mut total = 0;
$(total += $x;)*
total
}
};
}
#[test]
fn test_sum_macro() {
assert_eq!(sum!(1, 2, 3, 4, 5), 15);
assert_eq!(sum!(10, 20), 30);
assert_eq!(sum!(), 0);
}
}
6. 最佳实践和注意事项
6.1 宏设计原则
// 1. 保持简单:每个宏只做一件事
macro_rules! to_uppercase {
($s:expr) => {
$s.to_uppercase()
};
}
// 2. 提供清晰的错误信息
macro_rules! ensure {
($cond:expr, $msg:expr) => {
if !$cond {
panic!("条件失败: {} - {}", stringify!($cond), $msg);
}
};
}
// 3. 使用合适的重复模式
macro_rules! make_map {
($($key:expr => $value:expr),* $(,)?) => {
{
let mut map = std::collections::HashMap::new();
$(map.insert($key, $value);)*
map
}
};
}
// 4. 考虑宏的卫生性
macro_rules! with_temp_var {
($body:block) => {
{
let temp = 42; // 这个 temp 是卫生的
$body
}
};
}
fn main() {
// 使用 ensure!
let x = 10;
ensure!(x > 5, "x 应该大于 5");
// 使用 make_map!
let map = make_map! {
"one" => 1,
"two" => 2,
"three" => 3,
};
println!("map: {:?}", map);
// 卫生性演示
let temp = 100;
let result = with_temp_var!({
println!("内部 temp: {}", temp); // 这里的 temp 是宏内部定义的
temp * 2
});
println!("外部 temp: {}, 结果: {}", temp, result);
}
6.2 常见陷阱
// 陷阱1:重复计算
macro_rules! bad_max {
($a:expr, $b:expr) => {
if $a > $b { $a } else { $b }
};
}
macro_rules! good_max {
($a:expr, $b:expr) => {
{
let a = $a;
let b = $b;
if a > b { a } else { b }
}
};
}
// 陷阱2:运算符优先级
macro_rules! bad_double {
($x:expr) => {
$x * 2
};
}
macro_rules! good_double {
($x:expr) => {
($x) * 2
};
}
// 陷阱3:变量捕获
macro_rules! capture_problem {
() => {
let x = 10;
println!("内部 x: {}", x);
};
}
fn main() {
// 重复计算问题
let mut counter = 0;
let result = bad_max!(counter += 1, counter += 1);
println!("bad_max: counter = {}, result = {}", counter, result); // counter 增加了两次
let mut counter = 0;
let result = good_max!(counter += 1, counter += 1);
println!("good_max: counter = {}, result = {}", counter, result); // counter 只增加一次
// 运算符优先级问题
println!("bad_double(1+2) = {}", bad_double!(1 + 2)); // 1 + 2*2 = 5
println!("good_double(1+2) = {}", good_double!(1 + 2)); // (1+2)*2 = 6
// 变量捕获问题
let x = 100;
capture_problem!(); // 内部 x 会遮蔽外部 x
println!("外部 x: {}", x);
}
7. 总结
本章我们深入学习了 Rust 的宏系统:
- 声明式宏(macro_rules!):模式匹配和代码生成
- 过程宏:派生宏、属性宏、函数宏
- 高级技巧:递归宏、重复模式、卫生宏
- 实际项目:ORM 框架示例
- 调试和测试:宏展开、单元测试
- 最佳实践:设计原则、常见陷阱
宏是 Rust 元编程的强大工具,能够显著减少样板代码,提高代码的可维护性和表达力。正确使用宏可以让你的 Rust 代码更加优雅和高效。
下一章我们将学习 性能优化,探索如何编写高性能的 Rust 代码!


1万+

被折叠的 条评论
为什么被折叠?



