Rust如何在宏内部调用多个宏实现常量与数组批量生成
实现方案
完整代码
use std::sync::atomic::AtomicUsize; macro_rules! counters { // 宏入口:匹配成对的 [标识符, 字符串字面量] 参数,支持末尾逗号 ($($name:ident, $unit:literal),* $(,)?) => { counters!(@internal 0; []; []; $($name, $unit),*); }; // 递归终止分支:所有参数处理完成,生成静态数组 (@internal $cnt:expr; [ $($counter_init:expr),* ]; [ $($unit_str:expr),* ]; ) => { static mut COUNTERS: [AtomicUsize; $cnt] = [ $($counter_init),* ]; static UNITS: [&str; $cnt] = [ $($unit_str),* ]; }; // 递归处理分支:每轮处理一对参数,生成对应常量,收集数组元素 (@internal $cnt:expr; [ $($counter_init:expr),* ]; [ $($unit_str:expr),* ]; $name:ident, $unit:literal, $($rest:tt)* ) => { const $name: usize = $cnt; counters!(@internal $cnt + 1; [ $($counter_init,)* AtomicUsize::new(0) ]; [ $($unit_str,)* $unit ]; $($rest)*); }; } // 宏调用需要放在模块作用域,不能放在函数内部 counters!(NAME1, "unit1", NAME2, "unit2"); fn main() { // 常量验证 assert_eq!(NAME1, 0); assert_eq!(NAME2, 1); // 单位数组验证 assert_eq!(UNITS[NAME1], "unit1"); assert_eq!(UNITS[NAME2], "unit2"); // 计数器验证,static mut 访问需要 unsafe unsafe { COUNTERS[NAME1].fetch_add(1, std::sync::atomic::Ordering::Relaxed); assert_eq!(COUNTERS[NAME1].load(std::sync::atomic::Ordering::Relaxed), 1); } }
关键修改说明
- 参数匹配规则改为成对接收标识符和字符串字面量,完全匹配你需要的
counters!(NAME1, "unit1", NAME2, "unit2")调用格式 - 合并了常量生成和数组收集逻辑,递归过程中同时完成三个任务:生成对应索引的const常量、收集计数器初始化元素、收集单位字符串元素,避免多轮宏展开的上下文丢失问题
- 递归结束后一次性生成两个静态数组,长度自动匹配传入的参数对数
注意事项
- 生成的
COUNTERS是可变静态变量,Rust 要求所有对它的访问都必须包裹在unsafe块中,如果需要安全接口,可以额外封装结构体对外提供受控的访问方法 - 宏调用必须放在函数外部的模块作用域,因为const和static都属于Rust的顶级项,不允许定义在函数内部
- 支持传入参数末尾带逗号,兼容常见的宏调用书写习惯
内容的提问来源于stack exchange,提问作者user1685095
相关产品推荐
相关产品推荐

