我正在编写一个程序,它挂钩到一个发回
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"