有没有更简单的方法可以在反序列化时转换类型? [英] Is there is a simpler way to convert a type upon deserialization?

查看:162
本文介绍了有没有更简单的方法可以在反序列化时转换类型?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用 serde_json ,我有需要转换为String的JSON对象漂浮.我偶然发现了一个自定义解串器解决方案,但这似乎很简单. 这是下面代码的有效示例.

Using serde_json, I have JSON objects with Strings that I need to convert to floats. I've stumbled upon a custom deserializer solution, but it seems like a hack. Here is a working playground example of the code below.

#[macro_use]
extern crate serde_derive;
extern crate serde;
extern crate serde_json;

use serde_json::Error;
use serde::de::{Deserialize, DeserializeOwned, Deserializer};

#[derive(Serialize, Deserialize)]
struct Example {
    #[serde(deserialize_with = "coercible")]
    first: f64,
    second: f64,
}

fn coercible<'de, T, D>(deserializer: D) -> Result<T, D::Error>
where
    T: DeserializeOwned,
    D: Deserializer<'de>,
{
    use serde::de::Error;
    let j = String::deserialize(deserializer)?;
    serde_json::from_str(&j).map_err(Error::custom)
}

fn typed_example() -> Result<(), Error> {
    let data = r#"["3.141",1.618]"#;
    let e: Example = serde_json::from_str(data)?;
    println!("{} {}", e.first * 2.0, e.second * 2.0);
    Ok(())
}

fn main() {
    typed_example().unwrap();
}

上面的代码按照您的期望进行编译和运行,输出两个浮点数.

The above code compiles and runs as you would expect, outputting two floats.

我正在尝试了解解串器解决方案的工作原理,但是我想知道我是否朝着正确的方向前进,或者是否有更好的方法来实现这一目标.

I'm trying to learn how the deserializer solution works, but I'd like to know if I'm headed in the right direction or if there is a better way to do this.

推荐答案

使用coercible是偶然的.使用它,将输入"3.141"""删除,因此我将3.141馈入到serde_json::from_str(&j)中,后者适当地返回了浮点数.例如,当输入JSON包含意外值时,这种意外的解决方案很容易造成混乱,并且令人困惑.

Using coercible worked kind-of by accident. With it, the input "3.141" was stripped of its ""s, so I had 3.141 being fed into serde_json::from_str(&j), which appropriately returned a float. This accidental solution broke easily and confusingly when, e.g., the input JSON contained unexpected values.

我阅读了Serde文档(一个很好的学习练习),并提出了在反序列化JSON时将字符串转换为f64的适当方法(

I read the Serde docs (a great learning exercise) and came up with the appropriate way to convert a string to a f64 upon deserialization of JSON (working playground here):

#[macro_use]
extern crate serde_derive;
extern crate serde;
extern crate serde_json;

use std::fmt;
use serde_json::Error;
use serde::de::{self, Deserializer, Unexpected, Visitor};

#[derive(Serialize, Deserialize)]
struct Example {
    #[serde(deserialize_with = "string_as_f64")]
    first: f64,
    second: f64,
}

fn string_as_f64<'de, D>(deserializer: D) -> Result<f64, D::Error>
where
    D: Deserializer<'de>,
{
    deserializer.deserialize_f64(F64Visitor)
}

struct F64Visitor;
impl<'de> Visitor<'de> for F64Visitor {
    type Value = f64;
    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_str("a string representation of a f64")
    }
    fn visit_str<E>(self, value: &str) -> Result<f64, E>
    where
        E: de::Error,
    {
        value.parse::<f64>().map_err(|_err| {
            E::invalid_value(Unexpected::Str(value), &"a string representation of a f64")
        })
    }
}

fn typed_example() -> Result<(), Error> {
    let data = r#"["3.141",1.618]"#;
    let e: Example = serde_json::from_str(data)?;
    println!("{} {}", e.first * 2.0, e.second * 2.0);
    Ok(())
}

fn main() {
    typed_example().unwrap();
}

对Serde开发人员表示敬意,因为尽管 Serde文档在我看来似乎完全晦涩,非常有帮助和理解.我只需要从头开始,然后慢慢地通读.

Kudos to the Serde devs, because although the Serde documentation seemed totally obtuse to my eyes, it actually proved to be very helpful and comprehensible. I just had to start from the top and read through slowly.

这篇关于有没有更简单的方法可以在反序列化时转换类型?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆