You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 20:39:03