Is there is a simpler way to convert a type upon deserialization?

前端 未结 1 603
半阙折子戏
半阙折子戏 2021-01-05 07:55

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 hac

相关标签:
1条回答
  • 2021-01-05 08:17

    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.

    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();
    }
    

    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.

    0 讨论(0)
提交回复
热议问题