在进一步处理之前,我正在try 遍历一个JSON对象.以下代码:

use serde_json::{json, Map, Value, Result};


fn hex2value(_hex: &Value) -> Result<Value> {
    Ok(Value::from("converted"))
}

fn walk_object(obj: &mut Map<String, Value>) -> Result<()> {
    for (k, v) in obj.iter_mut() {
        if v.is_object() {
            walk_object(v.as_object_mut().unwrap())?
        } else if v.is_string() {
            obj[k] = hex2value(v)?
        }
    }
    Ok(())
}

fn main() {
    let mut data = json!({
        "name": "John Doe",
        "age": 43,
        "phones": {
            "home": "+44 1234567",
            "work": "+44 2345678"
        }
    });
    walk_object(&mut data.as_object().unwrap());
}

出现以下错误:

error[E0499]: cannot borrow `*obj` as mutable more than once at a time
  --> src/main.rs:13:13
   |
9  |     for (k, v) in obj.iter_mut() {
   |                   --------------
   |                   |
   |                   first mutable borrow occurs here
   |                   first borrow later used here
...
13 |             obj[k] = hex2value(v)?
   |             ^^^ second mutable borrow occurs here

如何更改代码以满足编译器的要求?

推荐答案

您只需将其分配给v即可.这会使k处于未使用状态,因此您可以使用values_mut来仅迭代这些值.

for v in obj.values_mut() {
    if v.is_object() {
        walk_object(v.as_object_mut().unwrap())?;
    } else if v.is_string() {
        *v = hex2value(v)?;
    }
}

考虑到用法,如果hex2valueString就更好了,这样你就不必在hex2value内再次判断Value是不是String.

fn hex2value(_hex: &mut String) -> Result<Value> {
    Ok(Value::from("converted"))
}

if v.is_object() {
    walk_object(v.as_object_mut().unwrap())?;
} else if let Value::String(s) = v {
    *v = hex2value(s)?;
}

这还允许您在需要时重用String缓冲区,尽管如果您要返回非字符串Value,则可能不需要这样做.

由于您将始终覆盖v,因此您也可以使用take来获得拥有的String.这将v中的String替换为空字符串,而hex2value则在实数String上操作.

fn hex2value(_hex: String) -> Result<Value> {
    Ok(Value::from("converted"))
}

if v.is_object() {
    walk_object(v.as_object_mut().unwrap())?;
} else if let Value::String(s) = v {
    *v = hex2value(std::mem::take(s))?;
}

如果您要做更复杂的事情,比如将String放入生成的Value中,这将非常有用.例如,您现在可以编写hex2value来重复使用String,这样就避免了Value::from中的分配.

fn hex2value(mut hex: String) -> Result<Value> {
    hex.clear();
    hex.push_str("converted");
    Ok(Value::from(hex))
}

注意,take通常也是一种方法,就像Value::takeOption::take一样.当您希望从&mut引用中获得拥有值时,它是最有用的,但也是避免borrow 判断器问题的一种很好的方法.

Rust相关问答推荐

trait 中self 的显式生命周期似乎导致E0499无法在循环中多次borrow * emits 器作为可变的

计算具有相邻调换且没有插入或删除的序列的距离

如何从使用mockall模拟的方法中返回self?

MutexGuard中的过滤载体不需要克隆

捕获FnMut闭包的时间不够长

铁 rust 中的泛型:不能将`<;T作为添加>;::Output`除以`{Float}`

随机函数不返回随机值

trait 对象指针的生命周期

如何在 Rust 中将枚举变体转换为 u8?

Some(v) 和 Some(&v) 有什么区别?

产生拥有值的迭代器的 Rust 可变borrow 在循环中失败

SDL2 没有在终端键上触发?

是否可以预测堆栈溢出?

`use std::error::Error` 声明中断编译

如何在 Rust 中编写涉及异步的重试函数

为什么基于 clap::Parser 读取的大量数字进行计算比硬编码该数字时慢?

在空表达式语句中移动的值

匹配结果时的简洁日志(log)记录

如何在不设置精度的情况下打印浮点数时保持尾随零?

令人困惑的错误消息? (解包运算符)