serde json反序列化任何数字[重复]

2024-02-11

我正在尝试结合字符串或结构体 https://serde.rs/string-or-struct.html手动反序列化结构体 https://serde.rs/deserialize-struct.html通过解析类似的示例:

{
  "secs": "12.34"
}

Or

{
  "secs": 5678
}

进入结构体:

struct Duration {
    secs: u64,
    nanos: u32,
}

其中两个secs and nanos成员是根据"secs"仅值。下面是我以这种方式实现自定义反序列化的非工作尝试,但我不确定如何委托给string_or_int函数为"secs" value.

use std::fmt;
use std::marker::PhantomData;
use std::str::FromStr;
use std::num::ParseIntError;
use serde::Deserialize;
use serde::de::{self, Deserializer, Visitor, MapAccess};

#[derive(Debug)]
struct Duration {
    secs: u64,
    nanos: u32,
}

impl<'de> Deserialize<'de> for Duration {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        enum Field { Secs };

        impl<'de> Deserialize<'de> for Field {
            fn deserialize<D>(deserializer: D) -> Result<Field, D::Error>
            where
                D: Deserializer<'de>,
            {
                struct FieldVisitor;

                impl<'de> Visitor<'de> for FieldVisitor {
                    type Value = Field;

                    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                        formatter.write_str("`secs`")
                    }

                    fn visit_str<E>(self, value: &str) -> Result<Field, E>
                    where
                        E: de::Error,
                    {
                        match value {
                            "secs" => Ok(Field::Secs),
                            _ => Err(de::Error::unknown_field(value, FIELDS)),
                        }
                    }
                }

                deserializer.deserialize_identifier(FieldVisitor)
            }
        }

        struct DurationVisitor;

        impl<'de> Visitor<'de> for DurationVisitor {
            type Value = Duration;

            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                formatter.write_str("struct Duration")
            }

            fn visit_map<V>(self, mut map: V) -> Result<Duration, V::Error>
            where
                V: MapAccess<'de>,
            {
                let mut secs = None;
                let mut nanos = None;
                while let Some(key) = map.next_key()? {
                    match key {
                        Field::Secs => {
                            // TODO somehow delegate to string_or_int and
                            // set secs and nanos based on secs value.
                            // if secs is int:
                            //   secs = the int value
                            //   nanos = 0
                            // if secs is string:
                            //   secs = the int value * 10^(digit count right of '.')
                            //   nanos = digit count right of '.'
                            // e.g. given value of 12.34
                            //   secs = 1234
                            //   nanos = 2
                        }
                    }
                }
                let secs = secs.ok_or_else(|| de::Error::missing_field("secs"))?;
                let nanos = nanos.ok_or_else(|| de::Error::missing_field("nanos"))?;
                Ok(Duration {
                    secs,
                    nanos,
                })
            }
        }

        const FIELDS: &'static [&'static str] = &["secs"];
        deserializer.deserialize_struct("Duration", FIELDS, DurationVisitor)
    }
}

fn string_or_int<'de, T, D>(deserializer: D) -> Result<T, D::Error>
where
    T: Deserialize<'de> + FromStr<Err = ParseIntError>,
    D: Deserializer<'de>,
{
    struct StringOrInt<T>(PhantomData<fn() -> T>);

    impl<'de, T> Visitor<'de> for StringOrInt<T>
    where
        T: Deserialize<'de> + FromStr<Err = ParseIntError>,
    {
        type Value = T;

        fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
            formatter.write_str("string or int")
        }

        fn visit_str<E>(self, value: &str) -> Result<T, E>
        where
            E: de::Error,
        {
            Ok(FromStr::from_str(value).unwrap())
        }
    }

    deserializer.deserialize_any(StringOrInt(PhantomData))
}

fn main() {
    let json_raw = r#"{ "secs": "1.000" }"#;
    let j: Duration = serde_json::from_str(&json_raw).unwrap();
    println!("{:?}", j);
}

如何委托字符串或 int 的自定义反序列化"secs"值,然后设置secs and nanos结构体成员值?


感谢@Shepmaster,简化的解决方案是:

use serde::{Deserialize, Deserializer};
use serde_json;

#[derive(Debug)]
struct Duration {
    secs: u64,
    nanos: u32,
}

#[derive(Deserialize)]
struct Raw<'a> {
    #[serde(borrow)]
    secs: StrOrNum<'a>,
}

#[derive(Deserialize)]
#[serde(untagged)]
enum StrOrNum<'a> {
    Str(&'a str),
    Num(u64),
}

impl<'de> Deserialize<'de> for Duration {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        let raw = Raw::deserialize(deserializer)?;

        match raw.secs {
            StrOrNum::Str(s) => {
                if s.parse::<f64>().is_ok() {
                    let mut p = s.splitn(2, ".").fuse();
                    let secs = p.next().map_or(0, |s| s.parse().unwrap_or(0));
                    let frac = p.next().map_or(0, |s| s.parse().unwrap_or(0));
                    let nanos = frac.to_string().len() as u32;
                    let secs = secs * 10_u64.pow(nanos) + frac;
                    Ok(Duration { secs, nanos })
                } else {
                    Err(serde::de::Error::custom(format!("Not a valid decimal: \"{}\"", s)))
                }
            }
            StrOrNum::Num(secs) => Ok(Duration { secs, nanos: 0 }),
        }
    }
}

fn main() {
    let json_raw = r#"{ "secs": 1234 }"#;
    let j: Duration = serde_json::from_str(&json_raw).unwrap();
    println!("{:?}", j);
    let json_raw = r#"{ "secs": "12.34" }"#;
    let j: Duration = serde_json::from_str(&json_raw).unwrap();
    println!("{:?}", j);
    let json_raw = r#"{ "secs": "12.3.4" }"#;
    let j: Duration = serde_json::from_str(&json_raw).unwrap();
    println!("{:?}", j);
}

None

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

serde json反序列化任何数字[重复] 的相关文章

随机推荐

  • Git - 拉取后缺少标签

    它不是 几乎 因为 stackoverflow 不允许 精确标题的重复 Git Pull 一切都是最新的 但事实并非如此 https stackoverflow com questions 8350567 git pull everythi
  • ImportError:动态模块没有定义 init 函数,但它确实定义了

    我正在尝试为供应商 C 库编写绑定 我已经成功地使用如下代码片段在其他模块中定义 init 函数 但在这个模块中它似乎不起作用 它编译得很好 但是当我尝试将其导入到测试中时就会抛出 ImportError脚本 这里可能出了什么问题 ifnd
  • DirectX 11 叠加

    我正在为游戏编写 DirectX 11 覆盖 创建纹理非常简单 而且我对 C C 有很好的了解 我遇到的问题是在我的测试窗口中我可以打印纹理 但是一旦我改变相机角度 纹理就会随之移动 这就是大多数人想要的 我想知道的是如何以 2D 打印某些
  • 如何将球形贴图投影到球体/立方体上:“等距矩形到立方体”

    更新 我找到 http os ivrpa org panosalado wiki http os ivrpa org panosalado wiki 在java中有一个实现 谁有类似的 c 或 c 东西 我有这张全景图 来自谷歌街景的球形地
  • 用Java创建虚拟打印机

    我想使用 Java 创建一个虚拟打印机 这样当您打印文件 使用 Word 或其他东西 时 Java 打印机就会被列为有效打印机 我的目标是获取程序 Word 等 直接发送到打印机的打印机格式化对象 我不知道这是否可能 对于这个问题来说 这似
  • 合并 git 中没有真正共同祖先的复制存储库的更改

    我有一个项目 DemoA 它是基于 git 存储库 Project1 构建的 不幸的是 DemoA 一开始只是 Project1 文件的副本 然后才变成一个实际的长期项目 我现在想让 Project1 成为 DemoA 的子模块 但更重要的
  • 如何创建命名引用类型元组?

    以下行创建一个命名的ValueTuple var tuple a 1 b 2 c 3 d 4 e 5 f 6 值类型无法有效传递 做C 7提供了一种创建命名元组的方法Tuple type 如果你的意思是是否有办法将其他名称附加到System
  • FaceBook API,应用内登录

    我跟着本指南 http developers facebook com docs guides mobile ios我已经通过 Facebook 集成成功创建了我的应用程序 有什么问题 当用户必须登录时 应用程序会在浏览器中退出 或在 Fa
  • 如何打开Lucene 4.3索引?

    我是 Lucene 新手 我正在尝试使用 Luke 打开 Lucene 4 3 索引 我使用简单的 Lucene 4 3 1 应用程序创建 但它一直给我 该位置的目录无效 请检查控制台以获取更多信息 最后一个异常 java lang Ill
  • 在物理设备上测试

    我是否正确理解 我必须支付 99 美元才能在物理设备上使用我的 Windows Phone 应用程序 我制作了一个小应用程序 想在我的新手机上测试 但它不是我计划发布的应用程序 因此我不会仅仅为了看到该应用程序在物理设备上运行而支付 99
  • 如何使用 xunit.runner.console 指定自定义参数

    我有一个 C Selenium Specflow 测试套件 我正在使用 xunit console exe 使用 Jenkins 运行该测试套件 我需要将这些测试指向不同的环境 测试 QA 产品等 并且想使用命令行参数 我调用的批处理命令是
  • Visual Studio 2017 中实体框架“数据库优先”的替代品是什么

    简单的问题 我正在使用 Visual Studio 2017 虽然我知道 EF 中的 数据库优先 方法已经消失 但我想知道替代方法是什么 我特别想做的是从现有数据库生成类 我看到这个 EntityFramework 反向 POCO 生成器
  • 使用“sudo”重复上一个命令

    我经常忘记运行命令sudo 我正在寻找一种方法来创建 bash 函数 或别名 来重复最后一个命令sudo 就像是 S sudo history 1 有任何想法吗 你可以写 sudo See 9 3 历史扩展 Bash 参考手册 http w
  • 可以使用 ggplot2 在 R 中创建此图表吗?

    假设我有以下内容dataframe in R df1 lt read csv jan csv stringsAsFactors FALSE header TRUE str df1 data frame 4 obs of 5 variable
  • 如何在 .Net MVC 中将文件从磁盘流式传输到客户端浏览器

    我的操作将文件从磁盘返回到客户端浏览器 目前我有 public FileResult MediaDownload byte fileBytes System IO File ReadAllBytes Server MapPath fileP
  • 使用 jQueryUI.autocomplete 和 Backbone JS 的 Javascript 模块

    假设我想使用jQueryUi autocomplete用于制作一个从 a 获取源代码的模块backboneCollection 我为自动完成模块实现了以下代码 1 并且以下为Backbone view 2 实际上 我不喜欢它 因为当用户不输
  • 自定义对话框窗口棱镜

    我已经实现了新的 DialogService 如本期所示WPF 的新 IDialogService https github com PrismLibrary Prism issues 1666 但是 这并没有解释如何编辑对话框本身的窗口
  • Raspberry Pi ARM 的 Mongodb MongoClient.connect() 上出现总线错误

    我尝试在 x64 计算机上执行此节点脚本 它似乎工作正常 然而 相同的脚本在 Raspberry Pi 上运行时报告总线错误 它给出了 6047 715610 未处理的故障 对齐异常错误 该错误作为总线错误报告在下一行 该错误似乎源于 Mo
  • Pyspark toPandas() 越界纳秒时间戳错误

    我正在尝试将 Spark DataFrame 转换为 Pandas 但是 它给出以下错误 OutOfBoundsDatetime Out of bounds nanosecond timestamp 有解决办法吗 如果我删除所有时间戳列 它
  • serde json反序列化任何数字[重复]

    这个问题在这里已经有答案了 我正在尝试结合字符串或结构体 https serde rs string or struct html和手动反序列化结构体 https serde rs deserialize struct html通过解析类似