🔍 什么是 fragment specifier?

macro_rules! 中,宏参数必须指明类型,例如:

($x:expr) => { ... }

这里的 :expr 就是 fragment specifier,告诉编译器这个 $x 是一个 表达式


🧩 常见的 fragment specifiers 对照表

Specifier 说明 示例
ident 标识符(变量名、函数名) x, foo, my_func
expr 表达式 "hello", 1 + 2, some_func(3)
ty 类型 i32, String, Vec<T>
pat 模式(用于 match, let 等) Some(x), Ok(val)
path 路径 std::io::Result, my_mod::foo
tt token tree,任意语法片段 println!("{}", x){ x + y }
block 语句块 { println!("hi"); }
item 顶级项(如函数、结构体) fn foo() {}struct Bar;
stmt 语句 let x = 3;, return y;
meta 元信息(用于属性) derive(Debug), cfg(test)
literal 字面量 5, "hello", true, 3.14

🎯 举例说明

1. expr(表达式)

macro_rules! double {
    ($x:expr) => {
        println!("{}", $x * 2);
    };
}

double!(3 + 4); // 输出 14

2. ident(标识符)

macro_rules! make_var {
    ($name:ident) => {
        let $name = 123;
    };
}

make_var!(my_var);

3. ty(类型)

macro_rules! make_vec {
    ($t:ty) => {
        let v: Vec<$t> = Vec::new();
    };
}

make_vec!(i32);

4. tt(token tree,万能)

macro_rules! print_tt {
    ($x:tt) => {
        println!("{:?}", stringify!($x));
    };
}

print_tt!(1 + 2 * 3); // 打印出原样的代码

📌 小贴士

  • 如果你不确定用什么,可以先用 tt,它最宽松。
  • expr 是最常见的,用于处理函数参数、值、加减乘除等。
  • 多个参数也可以各自指定类型:
macro_rules! add {
    ($a:expr, $b:expr) => {
        $a + $b
    };
}