如何编写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
相关产品推荐
相关产品推荐

