【问题标题】:How to deserialize a subfield of a struct from the original struct's JSON with Serde?如何使用 Serde 从原始结构的 JSON 反序列化结构的子字段?
【发布时间】:2017-06-01 08:41:55
【问题描述】:

我想从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)] 的东西,但是对于一个结构和一个字段而不是整个结构。

【问题讨论】:

标签: json rust serde


【解决方案1】:

从 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);
}

【讨论】:

    【解决方案2】:

    Serde documentation 有一章介绍当自动生成的属性不能完全满足您的要求时如何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);
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-11-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多