9

使用serde_jsonString ,我有需要转换为浮点数的带有 s 的 JSON 对象。我偶然发现了一个自定义反序列化器解决方案,但它似乎是一个 hack。 这是下面代码的工作游乐场示例。

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

上面的代码按照你的预期编译和运行,输出两个浮点数。

我正在尝试了解反序列化器解决方案的工作原理,但我想知道我是否朝着正确的方向前进,或者是否有更好的方法来做到这一点。

4

1 回答 1

10

coercible偶然使用某种工作。有了它,输入"3.141"被剥夺了它""的 s,所以我3.141被送入了serde_json::from_str(&j),它适当地返回了一个浮点数。例如,当输入 JSON 包含意外值时,这种意外的解决方案很容易被破坏并且令人困惑。

我阅读了 Serde 文档(一个很好的学习练习),并想出了将字符串转换f64为 JSON 反序列化后的适当方法(此处为工作场所):

#[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 文档在我看来完全是迟钝的,但事实证明它非常有用且易于理解。我只需要从头开始慢慢阅读。

于 2017-06-30T04:17:47.447 回答