使用macro_rules定义%中缀宏处理serde_json::Value遇语法错误求助
自定义serde_json处理宏的运算符解析错误问题
我尝试定义一个简易宏以更便捷地处理serde_json::Value对象,待基础版本运行后逐步添加更多运算符:
// requires `st: serde_json::Value` to be in scope macro_rules! std { (*$key:expr) => { st[$key.to_string()].as_str().unwrap_or_default().to_owned() }; ($a:literal % $b:expr) => { st[$a.to_string()].as_str().unwrap_or_default().to_owned() + $b.as_str().unwrap_or_default() }; }
我期望这样使用:std!(*"Address" + " #" % *"StreetAdditionalInfo"),但运行时报错:
cannot calculate the remainder of `&str` divided by `str`
请问我忽略了什么问题?
问题原因与修复方案
1. 核心问题:Rust表达式优先级与宏匹配逻辑冲突
你写的宏调用里,Rust会先按照内置运算符优先级解析表达式:%的优先级高于+,所以实际会被解析成std!( *"Address" + (" #" % *"StreetAdditionalInfo") )。这就导致" #" % *"StreetAdditionalInfo"先被当作普通Rust表达式处理,而&str类型没有%运算符,直接触发错误——你的宏根本没机会处理这个%符号。
同时,你的宏只定义了两种匹配规则,完全没有处理+运算符的情况,也不支持链式运算符的嵌套匹配,无法识别你期望的组合逻辑。
2. 修复后的宏实现
要实现预期的链式字符串拼接逻辑,需要扩展宏的规则,让它能递归匹配运算符组合:
// requires `st: serde_json::Value` to be in scope macro_rules! std { // 基础规则:提取serde_json::Value中的字符串 (*$key:expr) => { st[$key.to_string()].as_str().unwrap_or_default().to_owned() }; // 匹配字符串字面量(补充规则,处理" #"这类输入) ($lit:literal) => { $lit.to_owned() }; // 匹配"+"运算符组合,递归解析两边的内容 ($a:tt + $b:tt) => { std!($a) + std!($b) }; // 匹配"%"运算符组合,这里按你的需求实现为字符串拼接(可按需修改逻辑) ($a:tt % $b:tt) => { std!($a) + std!($b) }; }
3. 使用验证
现在可以按预期调用宏:
// 假设st是已初始化的serde_json::Value let result = std!(*"Address" + " #" % *"StreetAdditionalInfo");
宏会递归解析每一部分,将所有片段拼接成完整字符串。
额外说明
- 如果需要给
%定义不同于+的逻辑,比如添加特定分隔符或处理空值,直接修改对应宏分支的实现即可 - 使用
tt(token tree)匹配符可以灵活处理各类语法单元,支持多层嵌套的运算符组合 - 确保
st变量在宏调用的作用域中是有效的serde_json::Value实例
内容的提问来源于stack exchange,提问作者Alex R
相关产品推荐
相关产品推荐

