我正在编写一个程序,它挂钩到一个发回
JSON的Web服务.
当某个属性不存在时,它提供一个空对象,其所有字段为空字符串,而不是排除该值.当属性存在时,一些属性是u64.我怎么能拥有它以便Serde处理这个案子?
Rust Structs
#[derive(Clone,Debug,Deserialize)] struct WebResponse { foo: Vec<Foo>,} #[derive(Clone,Deserialize)] struct Foo { points: Points,Deserialize)] struct Points { x: u64,y: u64,name: String,}
示例JSON
{ "foo":[ { "points":{ "x":"","y":"","name":"" } },{ "points":{ "x":78,"y":92,"name":"bar" } } ] }
解决方法
Serde支持一个有趣的
attributes选择,可用于自定义类型的序列化或反序列化,同时仍然大部分使用派生实现.
在您的情况下,您需要能够解码可以指定为多种类型之一的字段,并且您不需要来自其他字段的信息来决定如何解码有问题的字段. #[serde(deserialize_with =“$path”)]注释非常适合解决您的问题.
我们需要定义一个函数,将空字符串或整数值解码为u64.我们可以对两个字段使用相同的函数,因为我们需要相同的行为.此函数将使用自定义Visitor
来处理字符串和整数.它有点长,但它让你欣赏Serde为你做的所有工作!
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,Deserialize)] struct Points { #[serde(deserialize_with = "deserialize_u64_or_empty_string")] x: u64,#[serde(deserialize_with = "deserialize_u64_or_empty_string")] y: u64,} 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,{ 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"