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

Rust中使用serde_json从无类型JSON提取数据时如何处理错误

问题描述

我有一个serde_json::Value类型的值,预期其内部包含一个对象数组,需要从这些对象中提取两个字段的值,任意步骤出错都要返回错误。我当前的代码如下:

use std::collections::HashMap;
use anyhow::Result;


fn get_stock(response: serde_json::Value) -> Result<HashMap<String, u32>>{
    response["products"]
        .as_array()?.iter()
        .map(|product| {
            let product = product.as_object()?;
            (
                product["name"].as_str()?.to_owned(),
                // 此处as_u64调用会失败
                product["stock"].as_str()?.parse::<u32>()?,
            )
        })
        .collect()?
}

之前使用.unwrap()时代码可以正常运行,但我将返回值改为Result类型、用?替换unwrap后,出现了如下编译错误:

error[E0277]: the `?` operator can only be used on `Result`s, not `Option`s, in a function that returns `Result`
  --> src/bin/products.rs:7:20
   |
5  | / fn get_stock(response: serde_json::Value) -> Result<HashMap<String, u32>>{
6  | |     response["products"]
7  | |         .as_array()?.iter()
   | |                    ^ use `.ok_or(...)?` to provide an error compatible with `Result<HashMap<std::string::String, u32>, anyhow::Error>`
8  | |         .map(|product| {
...  |
16 | |         .collect()?
17 | | }
   | |_- this function returns a `Result`
   |
   = help: the trait `FromResidual<Option<Infallible>>` is not implemented for `Result<HashMap<std::string::String, u32>, anyhow::Error>`
   = note: required by `from_residual`

error[E0277]: the `?` operator can only be used in a closure that returns `Result` or `Option` (or another type that implements `FromResidual`)
  --> src/bin/products.rs:9:46
   |
8  |           .map(|product| {
   |  ______________-
9  | |             let product = product.as_object()?;
   | |                                              ^ cannot use the `?` operator in a closure that returns `(std::string::String, u32)`
10 | |             (
11 | |                 product["name"].as_str()?.to_owned(),
...  |
14 | |             )
15 | |         })
   | |_________- this function should return `Result` or `Option` to accept `?`
   |
   = help: the trait `FromResidual<Option<Infallible>>` is not implemented for `(std::string::String, u32)`
   = note: required by `from_residual`

error: aborting due to 5 previous errors

我事先不知道JSON的精确结构,所以无法直接解析为结构体。仅确定它大概率是对象数组,每个对象包含字符串类型的name字段和整数类型的stock字段,需要将这两个字段提取为哈希映射,不符合预期结构时就返回错误。


实现方案
use anyhow::{anyhow, Result};
use std::collections::HashMap;

fn get_stock(response: serde_json::Value) -> Result<HashMap<String, u32>> {
    response
        .get("products")
        .ok_or(anyhow!("'products' 字段不存在"))?
        .as_array()
        .ok_or(anyhow!("'products' 不是数组类型"))?
        .iter()
        .map(|product| -> Result<(String, u32)> {
            let product = product.as_object().unwrap();
            Ok((
                product
                    .get("name")
                    .ok_or(anyhow!("'name' 字段不存在"))?
                    .as_str()
                    .ok_or(anyhow!("'name' 不是字符串类型"))?
                    .trim()
                    .to_owned(),
                // 此处as_u64调用不生效,因此转为字符串后解析
                product
                    .get("stock")
                    .ok_or(anyhow!("'stock' 字段不存在"))?
                    .as_str()
                    .ok_or(anyhow!("'stock' 不是字符串类型"))?
                    .parse::<u32>()?,
            ))
        })
        .collect()
}

逻辑说明

  • 用ok_or()方法将serde_json方法返回的Option类型转换为Result类型,通过anyhow!宏生成兼容返回值要求的错误信息
  • collect()可以直接接收元素为Result<(String, u32)>的迭代器,返回Result<HashMap<String, u32>>,符合预期执行逻辑:遇到第一个错误就直接返回错误,无错误时返回完整的哈希映射

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 11:48:03