如何使用 Serde 从原始结构的 JSON 反序列化结构的子字段?
How to deserialize a subfield of a struct from the original struct's JSON with Serde?
我想从 Test
对象本身的数据中反序列化 Test::team_size
属性:
#[derive(Debug, Serialize, Deserialize)]
struct TeamSize {
pub min: i64,
pub max: i64,
}
#[derive(Debug, Serialize, Deserialize)]
struct Test {
pub i: i64,
pub team_size: TeamSize,
}
fn main() {
let t: Test = serde_json::from_str(r#"{"i": -2, "min": 2, "max": 5}"#).unwrap();
assert_eq!(t.i, -2);
assert_eq!(t.team_size.min, 2);
assert_eq!(t.team_size.max, 5);
}
这段代码无法编译,我不知道如何让 Serde 做我想做的事。有没有办法从作为子字段的原始结构的 JSON 反序列化此示例中的 team_size
?
我似乎想要一些东西 类似 #[serde(untagged)]
但对于结构和字段而不是整个结构。
Serde documentation has a chapter on how to implement custom deserialization 当自动生成的属性没有完全满足您的要求时。从那里开始,它不是太复杂,只是乏味:
extern crate serde;
extern crate serde_json;
use std::fmt;
use serde::de::{self, Deserialize, Deserializer, Visitor, MapAccess};
#[derive(Debug)]
struct TeamSize {
pub min: i64,
pub max: i64,
}
#[derive(Debug)]
struct Test {
pub i: i64,
pub team_size: TeamSize,
}
impl<'de> Deserialize<'de> for Test {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where D: Deserializer<'de>
{
struct TestVisitor;
impl<'de> Visitor<'de> for TestVisitor {
type Value = Test;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("struct Test")
}
fn visit_map<V>(self, mut map: V) -> Result<Test, V::Error>
where V: MapAccess<'de>
{
let mut min = None;
let mut max = None;
let mut i = None;
while let Some(key) = map.next_key()? {
match key {
"min" => {
if min.is_some() {
return Err(de::Error::duplicate_field("min"));
}
min = Some(map.next_value()?);
}
"max" => {
if max.is_some() {
return Err(de::Error::duplicate_field("max"));
}
max = Some(map.next_value()?);
}
"i" => {
if i.is_some() {
return Err(de::Error::duplicate_field("i"));
}
i = Some(map.next_value()?);
}
_ => {
/* Ignore extra fields */
}
}
}
let min = min.ok_or_else(|| de::Error::missing_field("min"))?;
let max = max.ok_or_else(|| de::Error::missing_field("max"))?;
let i = i.ok_or_else(|| de::Error::missing_field("i"))?;
Ok(Test { i, team_size: TeamSize { min, max }})
}
}
const FIELDS: &'static [&'static str] = &["min", "max", "i"];
deserializer.deserialize_struct("Test", FIELDS, TestVisitor)
}
}
fn main() {
let t: Test = serde_json::from_str(r#"{"i": -2, "min": 2, "max": 5}"#).unwrap();
assert_eq!(t.i, -2);
assert_eq!(t.team_size.min, 2);
assert_eq!(t.team_size.max, 5);
}
从 Serde 1.0.34 开始,您现在可以使用 #[serde(flatten)]
:
#[derive(Debug, Serialize, Deserialize)]
struct Test {
pub i: i64,
#[serde(flatten)]
pub team_size: TeamSize,
}
在此之前,最简单的解决方法是反序列化为私有助手类型并根据需要对其进行重组:
#[macro_use]
extern crate serde_derive;
extern crate serde;
extern crate serde_json;
use serde::{Serialize, Serializer, Deserialize, Deserializer};
#[derive(Debug)]
pub struct TeamSize {
pub min: i64,
pub max: i64,
}
#[derive(Debug)]
pub struct Test {
pub i: i64,
pub team_size: TeamSize,
}
// Private helper
#[derive(Serialize, Deserialize)]
struct Helper {
pub i: i64,
pub min: i64,
pub max: i64,
}
impl Serialize for Test {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer
{
let helper = Helper {
i: self.i,
min: self.team_size.min,
max: self.team_size.max,
};
helper.serialize(serializer)
}
}
impl<'de> Deserialize<'de> for Test {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where D: Deserializer<'de>
{
let helper = Helper::deserialize(deserializer)?;
Ok(Test {
i: helper.i,
team_size: TeamSize {
min: helper.min,
max: helper.max,
},
})
}
}
fn main() {
let j = r#" { "i": -2, "min": 2, "max": 5 } "#;
let de: Test = serde_json::from_str(j).unwrap();
println!("{:#?}", de);
let ser = serde_json::to_string_pretty(&de).unwrap();
println!("{}", ser);
}
我想从 Test
对象本身的数据中反序列化 Test::team_size
属性:
#[derive(Debug, Serialize, Deserialize)]
struct TeamSize {
pub min: i64,
pub max: i64,
}
#[derive(Debug, Serialize, Deserialize)]
struct Test {
pub i: i64,
pub team_size: TeamSize,
}
fn main() {
let t: Test = serde_json::from_str(r#"{"i": -2, "min": 2, "max": 5}"#).unwrap();
assert_eq!(t.i, -2);
assert_eq!(t.team_size.min, 2);
assert_eq!(t.team_size.max, 5);
}
这段代码无法编译,我不知道如何让 Serde 做我想做的事。有没有办法从作为子字段的原始结构的 JSON 反序列化此示例中的 team_size
?
我似乎想要一些东西 类似 #[serde(untagged)]
但对于结构和字段而不是整个结构。
Serde documentation has a chapter on how to implement custom deserialization 当自动生成的属性没有完全满足您的要求时。从那里开始,它不是太复杂,只是乏味:
extern crate serde;
extern crate serde_json;
use std::fmt;
use serde::de::{self, Deserialize, Deserializer, Visitor, MapAccess};
#[derive(Debug)]
struct TeamSize {
pub min: i64,
pub max: i64,
}
#[derive(Debug)]
struct Test {
pub i: i64,
pub team_size: TeamSize,
}
impl<'de> Deserialize<'de> for Test {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where D: Deserializer<'de>
{
struct TestVisitor;
impl<'de> Visitor<'de> for TestVisitor {
type Value = Test;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("struct Test")
}
fn visit_map<V>(self, mut map: V) -> Result<Test, V::Error>
where V: MapAccess<'de>
{
let mut min = None;
let mut max = None;
let mut i = None;
while let Some(key) = map.next_key()? {
match key {
"min" => {
if min.is_some() {
return Err(de::Error::duplicate_field("min"));
}
min = Some(map.next_value()?);
}
"max" => {
if max.is_some() {
return Err(de::Error::duplicate_field("max"));
}
max = Some(map.next_value()?);
}
"i" => {
if i.is_some() {
return Err(de::Error::duplicate_field("i"));
}
i = Some(map.next_value()?);
}
_ => {
/* Ignore extra fields */
}
}
}
let min = min.ok_or_else(|| de::Error::missing_field("min"))?;
let max = max.ok_or_else(|| de::Error::missing_field("max"))?;
let i = i.ok_or_else(|| de::Error::missing_field("i"))?;
Ok(Test { i, team_size: TeamSize { min, max }})
}
}
const FIELDS: &'static [&'static str] = &["min", "max", "i"];
deserializer.deserialize_struct("Test", FIELDS, TestVisitor)
}
}
fn main() {
let t: Test = serde_json::from_str(r#"{"i": -2, "min": 2, "max": 5}"#).unwrap();
assert_eq!(t.i, -2);
assert_eq!(t.team_size.min, 2);
assert_eq!(t.team_size.max, 5);
}
从 Serde 1.0.34 开始,您现在可以使用 #[serde(flatten)]
:
#[derive(Debug, Serialize, Deserialize)]
struct Test {
pub i: i64,
#[serde(flatten)]
pub team_size: TeamSize,
}
在此之前,最简单的解决方法是反序列化为私有助手类型并根据需要对其进行重组:
#[macro_use]
extern crate serde_derive;
extern crate serde;
extern crate serde_json;
use serde::{Serialize, Serializer, Deserialize, Deserializer};
#[derive(Debug)]
pub struct TeamSize {
pub min: i64,
pub max: i64,
}
#[derive(Debug)]
pub struct Test {
pub i: i64,
pub team_size: TeamSize,
}
// Private helper
#[derive(Serialize, Deserialize)]
struct Helper {
pub i: i64,
pub min: i64,
pub max: i64,
}
impl Serialize for Test {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer
{
let helper = Helper {
i: self.i,
min: self.team_size.min,
max: self.team_size.max,
};
helper.serialize(serializer)
}
}
impl<'de> Deserialize<'de> for Test {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where D: Deserializer<'de>
{
let helper = Helper::deserialize(deserializer)?;
Ok(Test {
i: helper.i,
team_size: TeamSize {
min: helper.min,
max: helper.max,
},
})
}
}
fn main() {
let j = r#" { "i": -2, "min": 2, "max": 5 } "#;
let de: Test = serde_json::from_str(j).unwrap();
println!("{:#?}", de);
let ser = serde_json::to_string_pretty(&de).unwrap();
println!("{}", ser);
}