使用Serde进行自定义数组或值数组反序列化

7
我希望构建一个自定义反序列化器,将值数组的数组反序列化为Vec<Child>,其中我已经编写了一个自定义serde反序列化器,将值数组解析为Child
一种想法是直接为Vec<Child>添加一个客户端反序列化器,但我想知道是否存在更优雅的解决方案。
作为说明,我正在尝试制作类似于下面的内容,但在Parent中使用字段array而不是single
extern crate serde_json; // 1.0.32
extern crate serde; // 1.0.80
#[macro_use] extern crate serde_derive;

use serde::de::{Deserializer, SeqAccess, Visitor};
use std::fmt;

#[derive(Debug, Deserialize)]
struct Parent {
    #[serde(deserialize_with = "parse_child")]
    single: Child,
    //#[serde(deserialize_with = "parse_child")]
    //array: Vec<Child>,
}

#[derive(Default, Debug, Deserialize)]
struct Child {
    a: u64,
    b: f32,
    c: usize,
}

fn parse_child<'de, D>(deserializer: D) -> Result<Child, D::Error>
where
    D: Deserializer<'de>,
{
    struct ChildParser;
    impl<'de> Visitor<'de> for ChildParser
    {
        type Value = Child;

        fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
            formatter.write_str("[u64, f32, usize]")
        }

        fn visit_seq<A: SeqAccess<'de>>(self, mut seq: A) -> Result<Self::Value, A::Error> {
            println!("In custom deserializer");
            let mut child = Child { ..Default::default() };

            let tmp = seq.next_element::<u64>()?;
            if let Some(a) = tmp {
                child.a = a;
            };

            let tmp = seq.next_element::<f32>()?;
            if let Some(b) = tmp {
                child.b = b;
            };

            let tmp = seq.next_element::<usize>()?;
            if let Some(c) = tmp {
                child.c = c;
            };

            Ok(child)
        }
    }

    deserializer.deserialize_any(ChildParser{})
}

fn main() {
    let child_data = r#"[49, 11.75, 0]"#;
    let child : Child = serde_json::from_str(child_data).unwrap();
    println!("Child = {:?}", &child);

    let parent_data = r#"{"single": [49, 11.75, 0]}"#;
    let parent : Parent = serde_json::from_str(parent_data).expect("to be able to deserialize it");
    println!("Parent = {:?}", &parent);

}

链接到一个playground

我想要反序列化的样本输入:[[49,11.75,0],[42,9,1]]


1
@Stargateur,给你了。你有什么解决这个问题的想法吗? - Boris
这样好多了,但你的问题仍然不清楚。我们不知道你想要反序列化 r#"{"single": [49, 11.75, 0]}"# 还是 r#"[[49, 11.75, 0], [42, 9, 1]]"# 还是两者都要。 - Stargateur
2
你使用 let parent: Vec<Child> = serde_json::from_str(parent_data).unwrap() 时遇到了什么问题? - Stargateur
2个回答

7
我会这样实现:

我会这样实现:

#[macro_use]
extern crate serde_derive;

extern crate serde;
extern crate serde_json;

#[derive(Deserialize, Debug)]
#[serde(transparent)]
struct Parent {
    array: Vec<Child>,
}

#[derive(Deserialize, Debug)]
struct Child {
    a: u64,
    b: f32,
    c: usize,
}

fn main() {
    let j = r#" [[49, 11.75, 0], [42, 9, 1]] "#;
    println!("{:#?}", serde_json::from_str::<Parent>(j).unwrap());
}

更简洁地说:
#[macro_use]
extern crate serde_derive;

extern crate serde;
extern crate serde_json;

#[derive(Deserialize, Debug)]
struct Child {
    a: u64,
    b: f32,
    c: usize,
}

fn main() {
    let j = r#" [[49, 11.75, 0], [42, 9, 1]] "#;
    let array: Vec<Child> = serde_json::from_str(j).unwrap();
    println!("{:#?}", array);
}

非常感谢@dtolnay,这确实是一个非常巧妙的方法。我不知道(或者说不理解)serde可以直接从数组反序列化结构体。 - Boris
我建议在链接的重复部分中添加“透明”的例子。 - Shepmaster

0

我不确定这是否是您想要的,但使用反序列化映射的文档

extern crate serde; // 1.0.80
extern crate serde_json; // 1.0.32

use serde::de::{Deserialize, Deserializer, SeqAccess, Visitor};
use std::fmt;

#[derive(Debug)]
struct Child {
    a: u64,
    b: f32,
    c: usize,
}

struct ChildVisitor;

impl<'de> Visitor<'de> for ChildVisitor {
    type Value = Child;

    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_str("[u64, f32, usize]")
    }

    fn visit_seq<A: SeqAccess<'de>>(self, mut access: A) -> Result<Self::Value, A::Error> {
        let a = access.next_element::<u64>()?.unwrap_or(Default::default());

        let b = access.next_element::<f32>()?.unwrap_or(Default::default());

        let c = access
            .next_element::<usize>()?
            .unwrap_or(Default::default());

        Ok(Child { a, b, c })
    }
}

impl<'de> Deserialize<'de> for Child {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        deserializer.deserialize_seq(ChildVisitor {})
    }
}

#[derive(Debug)]
struct Parent {
    childs: Vec<Child>,
}

struct ParentVisitor {}

impl<'de> Visitor<'de> for ParentVisitor {
    type Value = Parent;

    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_str("[[Child]]")
    }

    fn visit_seq<A: SeqAccess<'de>>(self, mut access: A) -> Result<Self::Value, A::Error> {
        let mut childs = Vec::with_capacity(access.size_hint().unwrap_or(0));

        while let Some(child) = access.next_element::<Child>()? {
            childs.push(child);
        }

        Ok(Parent { childs })
    }
}

impl<'de> Deserialize<'de> for Parent {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        deserializer.deserialize_seq(ParentVisitor {})
    }
}

fn main() {
    let child_data = r#"[49, 11.75, 0]"#;
    let child: Child = serde_json::from_str(child_data).unwrap();
    println!("Child = {:#?}", child);

    let parent_data = r#"[[49, 11.75, 0], [42, 9, 1]]"#;
    let parent: Parent = serde_json::from_str(parent_data).unwrap();
    println!("Parent = {:#?}", parent);
}

谢谢@Stargateur的建议,我只需要手动实现Child类的Deserialize方法而不是派生它。 - Boris

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接