Files
rust/Macro/readme.md
2025-10-05 23:51:24 +08:00

2.8 KiB
Raw Blame History

完全可以,我们来系统讲一下 macro_rules!宏变量匹配类型,也就是你说的除了 expr 还能匹配什么。


1 基本宏变量语法

$变量名:匹配类型
  • $ → 宏变量前缀
  • 变量名 → 自己命名
  • 匹配类型 → Rust 定义的一些匹配规则,告诉宏要匹配什么类型的语法单元

2 常用匹配类型

匹配类型 描述 示例
expr 表达式 5 + 3, a * b, func(1)
ident 标识符 x, my_var
ty 类型 i32, Vec<String>
pat 模式 Some(x), (a, b)
stmt 语句 let x = 1;
block 代码块 { let x = 1; x+2 }
meta 元属性 derive(Debug)
tt Token Tree最通用 单个标记或标记组,几乎可以匹配任何东西
path 路径 std::io::Result, crate::module::Foo
literal 字面量 "hello", 42, 3.14

3 示例

表达式匹配

macro_rules! add {
    ($a:expr, $b:expr) => {
        $a + $b
    };
}

let x = add!(1 + 2, 3 * 4); // 匹配复杂表达式

类型匹配

macro_rules! make_default {
    ($t:ty) => {
        <$t>::default()
    };
}

let v: Vec<i32> = make_default!(Vec<i32>);

标识符匹配

macro_rules! create_var {
    ($name:ident) => {
        let $name = 42;
    };
}

create_var!(my_var);
println!("{}", my_var); // 输出 42

语句匹配

macro_rules! repeat_stmt {
    ($s:stmt) => {
        $s
        $s
    };
}

repeat_stmt!(println!("Hi");) // 会打印两次 Hi

代码块匹配

macro_rules! run_block {
    ($b:block) => {
        println!("Before");
        $b
        println!("After");
    };
}

run_block!({
    println!("Inside");
});

输出:

Before
Inside
After

4 小结

  • expr 只能匹配表达式
  • Rust 宏提供了多种匹配类型(ident, ty, pat, stmt, block, literal, tt 等)
  • tt 最通用,但匹配后需要自己处理结构

可以理解为:每个匹配类型限制了宏能匹配的语法单元,避免写宏时乱匹配或产生歧义


我可以画一张 macro_rules! 匹配类型示意图,把 expr, ident, ty, pat, stmt, block, tt, literal 的对应语法单元和示例都标出来,一目了然。

你希望我画吗?