如何遍历Rust serde对象键并修改字符串值?解决借用冲突
解决Serde JSON对象的HTML清理及可变借用冲突问题
错误原因
你遇到的编译错误是Rust借用规则导致的:当你通过doc.as_object_mut().unwrap()获取JSON对象的可变引用并遍历其键值对时,已经持有了整个对象的可变借用;此时再通过doc[field_name]尝试修改值,相当于再次请求对象的可变引用,违反了Rust“同一时间只能有一个可变引用”的规则,因此编译失败。
最优实现方式
直接遍历JSON对象的可变键值对,在遍历过程中直接修改字符串值,无需额外操作原对象,既符合借用规则,又高效简洁:
if let Some(docs) = chunk.response.docs.as_array_mut() { for doc in docs.iter_mut() { // 仅处理Object类型的JSON对象,避免非预期类型导致panic if let Some(obj) = doc.as_object_mut() { for (_key, value) in obj { // 匹配字符串类型的值,获取可变引用 if let Value::String(ref mut s) = value { // 替换为HTML清理后的字符串 *s = sanitize_html::sanitize_str(s); } } } } }
代码说明
doc.as_object_mut()返回Option<&mut Map<String, Value>>,用if let替代unwrap()可以避免非Object类型时程序崩溃- 遍历
obj的键值对时,value是&mut Value类型的可变引用,直接匹配Value::String(ref mut s)就能拿到字符串的可变引用 - 对
s解引用(*s)赋值,直接修改原字符串内容,不会触发借用冲突
备选方案(需收集键的场景)
如果需要先处理键的逻辑(比如过滤某些字段),可以先收集所有键的副本,再遍历键修改对应值:
if let Some(docs) = chunk.response.docs.as_array_mut() { for doc in docs.iter_mut() { if let Some(obj) = doc.as_object_mut() { // 收集所有键的克隆副本 let keys: Vec<String> = obj.keys().cloned().collect(); for key in keys { if let Some(Value::String(ref mut s)) = obj.get_mut(&key) { *s = sanitize_html::sanitize_str(s); } } } } }
这种方式适合需要对键做额外处理的场景,但会额外占用内存存储键的副本,性能略低于第一种方案。
内容的提问来源于stack exchange,提问作者LollyPop Lolly
相关产品推荐
相关产品推荐

