2.8 KiB
		
	
	
	
	
	
	
	
			
		
		
	
	
			2.8 KiB
		
	
	
	
	
	
	
	
完全可以,我们来系统讲一下 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 的对应语法单元和示例都标出来,一目了然。
你希望我画吗?