🔍 什么是 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
};
}