rust精通教程 (2)

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 代码!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

王小玗

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值