有没有更简单的方法可以在反序列化时转换类型? [英] Is there is a simpler way to convert a type upon deserialization?
问题描述
使用 serde_json ,我有需要转换为String
的JSON对象漂浮.我偶然发现了一个自定义解串器解决方案,但这似乎很简单. 这是下面代码的有效示例.
Using serde_json, I have JSON objects with String
s 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屋!