从 serde_json 中的无类型 JSON 中提取数据时如何处理错误?

你好随机

我有一个serde_json::Value我希望包含一组对象的对象。我想从这些对象中提取 2 个值并在任何失败时返回错误。到目前为止,这是我的代码:

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 fails for some reason
                product["stock"].as_str()?.parse::<u32>()?,
            )
        })
        .collect()?
}

当我使用.unwrap()它时工作正常,但是在将返回类型更改为Result并替换为 unwraps 后,?我收到以下编译错误:

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[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:11:41
   |
8  |           .map(|product| {
   |  ______________-
9  | |             let product = product.as_object()?;
10 | |             (
11 | |                 product["name"].as_str()?.to_owned(),
   | |                                         ^ cannot use the `?` operator in a closure that returns `(std::string::String, u32)`
...  |
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[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:13:42
   |
8  |           .map(|product| {
   |  ______________-
9  | |             let product = product.as_object()?;
10 | |             (
11 | |                 product["name"].as_str()?.to_owned(),
12 | |                 //as_u64 fails for some reason
13 | |                 product["stock"].as_str()?.parse::<u32>()?,
   | |                                          ^ cannot use the `?` operator in a closure that returns `(std::string::String, u32)`
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[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:13:58
   |
8  |           .map(|product| {
   |  ______________-
9  | |             let product = product.as_object()?;
10 | |             (
11 | |                 product["name"].as_str()?.to_owned(),
12 | |                 //as_u64 fails for some reason
13 | |                 product["stock"].as_str()?.parse::<u32>()?,
   | |                                                          ^ cannot use the `?` operator in a closure that returns `(std::string::String, u32)`
miav@battlestation catbot % cargo run --bin products
   Compiling catbot v0.1.0 (/Users/miav/Documents/Personal/Projects/programming/catbot)
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[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:11:41
   |
8  |           .map(|product| {
   |  ______________-
9  | |             let product = product.as_object()?;
10 | |             (
11 | |                 product["name"].as_str()?.to_owned(),
   | |                                         ^ cannot use the `?` operator in a closure that returns `(std::string::String, u32)`
...  |
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[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:13:42
   |
8  |           .map(|product| {
   |  ______________-
9  | |             let product = product.as_object()?;
10 | |             (
11 | |                 product["name"].as_str()?.to_owned(),
12 | |                 //as_u64 fails for some reason
13 | |                 product["stock"].as_str()?.parse::<u32>()?,
   | |                                          ^ cannot use the `?` operator in a closure that returns `(std::string::String, u32)`
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[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:13:58
   |
8  |           .map(|product| {
   |  ______________-
9  | |             let product = product.as_object()?;
10 | |             (
11 | |                 product["name"].as_str()?.to_owned(),
12 | |                 //as_u64 fails for some reason
13 | |                 product["stock"].as_str()?.parse::<u32>()?,
   | |                                                          ^ cannot use the `?` operator in a closure that returns `(std::string::String, u32)`
14 | |             )
15 | |         })
   | |_________- this function should return `Result` or `Option` to accept `?`
   |
   = help: the trait `FromResidual<Result<Infallible, ParseIntError>>` is not implemented for `(std::string::String, u32)`
   = note: required by `from_residual`

error: aborting due to 5 previous errors

我事先不知道 JSON 的确切结构,因此无法将其解析为结构体。我所知道的是,它很可能是一个对象数组,其中包含一个name字符串字段和一个stock整数字段,我想将其提取到地图中。如果情况并非如此,那么我想返回一个错误。什么是最简单的方法来做到这一点?

更新:在遵循 Lagerbaer 的建议并进行了一些挖掘之后,我想出了以下解决方案。

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' not found"))?
        .as_array()
        .ok_or(anyhow!("'products' is not an array"))?
        .iter()
        .map(|product| -> Result<(String, u32)> {
            let product = product.as_object().unwrap();
            Ok((
                product
                    .get("name")
                    .ok_or(anyhow!("'name' not found"))?
                    .as_str()
                    .ok_or(anyhow!("'name' is not a string"))?
                    .trim()
                    .to_owned(),
                //as_u64 fails for some reason
                product
                    .get("stock")
                    .ok_or(anyhow!("'stock' not found"))?
                    .as_str()
                    .ok_or(anyhow!("'stock' is not a string"))?
                    .parse::<u32>()?,
            ))
        })
        .collect()
}

用于ok_or()映射OptionResult,必须使用anyhow!宏使其与无论如何结果类型兼容。事实证明,它collect()实际上接受了一个迭代器,Result<(String, u32)>以产生Result<HashMap<String, u32>>具有我想要的确切行为的a ,即,如果没有错误,则返回第一个错误或完整的哈希映射。

拉格贝尔

所以这里有几个问题,编译器会尽力告诉你。

我会让你从第一个开始,然后我鼓励你尝试单独进行一段时间。

所以第一个错误显然是as_array返回 anOption和 not Result,因此,您不能在?那里使用运算符。

幸运的是,编译器会告诉您该做什么:Option有一个ok_or您应该调用的方法它将Option变成Result. 如果Option是,Some(value)你会得到一个Ok(value),如果OptionNone,你会得到你在ok_or参数中指定的任何错误

另一个容易发现的错误是:您的函数返回 a Result,因此显然返回值应该是 a Result因此?应该删除最后的最后一个,因为这?需要 aResult并将其转换为“纯”值(如果结果为Ok)。

然后剩下的就是弄清楚闭包应该返回什么。也许您可以在修复我上面解释的其他错误后尝试一下。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

Serde Stream Deserializer的类型不是serde_json :: Value

如何重命名serde_json :: Map中的所有键?

如何修改 serde_json::Value::String 中的字符串?

如何在不导出结构的情况下使用serde_json获得JSON文件中的特定项目?

在函数中返回由serde_json创建的结构

在 rust 中从 API 反序列化 serde_json

如何返回包含serde_json :: Value的结果?

如何在托盘中使用 serde_json?

如何将serde_json :: Value转换为实现反序列化特征的具体类型?

为什么在尝试使用serde_json解析数据时总是出现“尾随字符”错误?

如何使用serde_json和Value枚举处理可能丢失的字段?

尝试使用 serde_json 解析字符串时出现“尾随字符”错误

强类型对象的通用 serde_json 反序列化函数

在 Rust 中使用 serde_json 时如何避免双 '\' 转义?

在 rust 中扩展递归宏,类似于 serde_json 但适用于 HTML 元素

使用serde_json解析时是否可以展平子对象字段?

如何解决hyper :: Body的特性std :: convert :: From <serde_json :: Value>没有实现?

如何进行模式匹配以获得serde_json解析的数字?

如何仅对serde_json实现自定义序列化?

如何将serde_json :: error :: Error转换为reqwest :: error :: Error?

如何使用相同的可变借位两次调用serde_json :: to_writer?

为什么 homrebrew 公式测试失败并出现 serde_json 错误“第 1 行第 1 列的预期值”

当使用将在函数末尾删除的String调用时,如何返回serde_json :: from_str的结果?

使用serde_json解析对象内部的对象

如何处理JSON中的缺失数据

如何处理python中的json数据?

使用serde_json :: from_str反序列化为带有&'static字符串的结构会导致生命周期错误

如何处理 Java Rest Web Service 中错误 JSON 数据的错误:Jackson JSON Parser Unrecognized token

从JSON + Swift或ObjC检索数据时如何处理CoreData中的关系