Serde поддерживает интересный набор атрибутов, которые можно использовать для настройки сериализации или десериализации для типа, пока используя производную реализацию по большей части.
В вашем случае вам необходимо иметь возможность декодировать поле, которое может быть указано как один из нескольких типов, и вам не нужна информация из других полей, чтобы решить, как декодировать проблемные поля. Аннотация #[serde(deserialize_with="$path")]
хорошо подходит для решения вашей проблемы.
Нам нужно определить функцию, которая будет декодировать либо пустую строку, либо целочисленное значение в u64
. Мы можем использовать одну и ту же функцию для обоих полей, поскольку нам нужно одинаковое поведение. Эта функция будет использовать пользовательский Visitor
, чтобы иметь возможность для обработки как строк, так и целых чисел. Это немного длинновато, но заставляет вас ценить всю работу, которую Серде делает для вас!
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
use serde::Deserializer;
use serde::de::{self, Unexpected};
use std::fmt;
#[derive(Clone, Debug, Deserialize)]
struct WebResponse {
foo: Vec<Foo>,
}
#[derive(Clone, Debug, Deserialize)]
struct Foo {
points: Points,
}
#[derive(Clone, Debug, Deserialize)]
struct Points {
#[serde(deserialize_with = "deserialize_u64_or_empty_string")]
x: u64,
#[serde(deserialize_with = "deserialize_u64_or_empty_string")]
y: u64,
name: String,
}
struct DeserializeU64OrEmptyStringVisitor;
impl<'de> de::Visitor<'de> for DeserializeU64OrEmptyStringVisitor {
type Value = u64;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("an integer or a string")
}
fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
where
E: de::Error,
{
Ok(v)
}
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where
E: de::Error,
{
if v == "" {
Ok(0)
} else {
Err(E::invalid_value(Unexpected::Str(v), &self))
}
}
}
fn deserialize_u64_or_empty_string<'de, D>(deserializer: D) -> Result<u64, D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_any(DeserializeU64OrEmptyStringVisitor)
}
fn main() {
let value = serde_json::from_str::<WebResponse>(
r#"{
"foo": [
{
"points": {
"x": "",
"y": "",
"name": ""
}
},
{
"points": {
"x": 78,
"y": 92,
"name": "bar"
}
}
]
}"#,
);
println!("{:?}", value);
}
Cargo.toml
:
[dependencies]
serde = "1.0.15"
serde_json = "1.0.4"
serde_derive = "1.0.15"
person
Francis Gagné
schedule
17.06.2016
u64
? Вы хотите установить в поле значение0
? комуNone
? что-то другое? - person Francis Gagné   schedule 17.06.20160
. - person XAMPPRocky   schedule 17.06.2016