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

如何编写Rust宏实现多格式参数批量格式化?

Rust宏实现格式化字符串批量转换问题

简而言之

我想要编写一个Rust宏,实现如下转换:

magic_formatter!("_{}", "{}_", "_{}_"], "foo") == 
    [format!("_{}", "foo"), 
     format!("{}_{}", "foo"), 
     format!("_{}_{}", "foo")]

(能生成["_foo", "foo_", "_foo_"]且支持可变参数的方案也可)

完整背景

我正在编写一个解析器,其测试代码存在大量重复,例如:

let ident = identifier().parse("foo ").unwrap();
    assert_eq!(ident, Syntax::ident("foo"));
    let ident = identifier().parse(" foo").unwrap();
    assert_eq!(ident, Syntax::ident("foo"));
    let ident = identifier().parse(" foo ").unwrap();
    assert_eq!(ident, Syntax::ident("foo"));

我尝试用循环简化代码,但如下写法无法编译:

for f in [" {}", "{} ", " {} "] {
        let inp = format!(f, "foo");
        let ident = identifier().parse(inp).unwrap();
        assert_eq!(ident, Syntax::ident("foo"));
    }

由于所有信息可在编译时确定,我查找资料后尝试编写Rust宏,但多次尝试均未成功,我的最新尝试代码如下:

macro_rules! map_fmt {
    (@accum () -> $($body:tt),*) => { map_fmt!(@as_expr [$($body),*]) };

    (@accum ([$f:literal, $($fs:literal),*], $args:tt) -> $($body:tt),*) => {
        map_fmt!(@accum ([$($fs),*], $args) -> (format!($f, $args) $($body),*))
    };

    (@as_expr $e:expr) => { $e };

    ([$f:literal, $($fs:literal),*], $args:expr) => {
        map_fmt!(@accum ([$f, $($fs),*], $args) -> ())
    };
}

希望有人能帮我分析宏的问题所在、修复方法,或提供其他优化测试代码的技巧。

补充:最终解决方案

以下是我使用的最终宏,基于@finomnis的正确答案修改,支持format!的可变参数:

macro_rules! map_fmt {
    (@accum ([$f:literal], $($args:tt),*) -> ($($body:tt)*)) => { [$($body)* format!($f, $($args),*)] };

    (@accum ([$f:literal, $($fs:literal),*], $($args:tt),*) -> ($($body:tt)*)) => {
            map_fmt!(@accum ([$($fs),*], $($args),*) -> ($($body)* format!($f, $($args),*),))
    };

    ([$f:literal, $($fs:literal),*], $($args:expr),*) => {
            map_fmt!(@accum ([$f, $($fs),*], $($args),*) -> ())
    };
}

内容的提问来源于stack exchange,提问作者NivPgir

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 22:39:25