58·进阶

声明宏 macro_rules!

声明宏 macro_rules!

学习目标

  1. 理解声明宏的作用
  2. 掌握模式匹配语法
  3. 编写常用宏

核心概念

基本语法

// 定义宏
macro_rules! say_hello {
    () => {
        println!("Hello!");
    };
}

// 使用
fn main() {
    say_hello!();
}

带参数

macro_rules! greet {
    ($name:expr) => {
        println!("Hello, {}!", $name);
    };
    ($name:expr, $greeting:expr) => {
        println!("{}, {}!", $greeting, $name);
    };
}

fn main() {
    greet!("Rust");
    greet!("Rust", "Hi");
}

重复模式

macro_rules! vec_of_strings {
    ($($s:expr),* $(,)?) => {
        vec![$($s.to_string()),*]
    };
}

fn main() {
    let v = vec_of_strings!["hello", "world", "rust"];
    println!("{:?}", v);
}

常用宏示例

// HashMap 字面量宏
macro_rules! hashmap {
    ($($key:expr => $value:expr),* $(,)?) => {{
        let mut map = std::collections::HashMap::new();
        $(map.insert($key, $value);)*
        map
    }};
}

fn main() {
    let scores = hashmap! {
        "Alice" => 95,
        "Bob" => 87,
    };
    println!("{:?}", scores);
}

捕获类型

macro_rules! debug_print {
    ($var:ident) => {
        println!("{} = {:?}", stringify!($var), $var);
    };
    ($expr:expr) => {
        println!("{} = {:?}", stringify!($expr), $expr);
    };
}

fn main() {
    let x = 42;
    debug_print!(x);
    debug_print!(2 + 3);
}

实践练习

练习 1:计时宏

macro_rules! time_it {
    ($label:expr, $block:block) => {{
        let start = std::time::Instant::now();
        let result = $block;
        let elapsed = start.elapsed();
        println!("{}: {:?}", $label, elapsed);
        result
    }};
}

fn main() {
    let sum = time_it!("求和", {
        (1..=1_000_000).sum::<i64>()
    });
    println!("结果: {}", sum);
}

练习 2:自动实现 Display

macro_rules! impl_display {
    ($type:ty, $format:expr) => {
        impl std::fmt::Display for $type {
            fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
                write!(f, $format, self)
            }
        }
    };
}

struct Point {
    x: f64,
    y: f64,
}

impl_display!(Point, "({}, {})");
// 这需要更复杂的宏来解构 self

fn main() {
    let p = Point { x: 1.0, y: 2.0 };
    println!("{}", p);
}

小结

语法说明
$name:expr捕获表达式
$name:ident捕获标识符
$name:ty捕获类型
$($x:expr),*重复(逗号分隔)
$($x:expr),+重复(至少一个)
$(...)?可选
stringify!转字符串

练习编辑器

rust
Loading...