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

Bor*_*ris 7 rust serde

我想构建一个自定义反序列化器来Vec<Child>将值数组的数组反序列化为Child.

一个想法是Vec<Child>直接添加一个客户解串器,但我想知道是否存在更优雅的解决方案。


作为一个例子,我正在尝试制作类似下面的内容,但array在 Parent 中使用字段而不是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);

}
Run Code Online (Sandbox Code Playgroud)

链接到游乐场

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

dto*_*nay 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());
}
Run Code Online (Sandbox Code Playgroud)

或者更简洁地说:

#[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);
}
Run Code Online (Sandbox Code Playgroud)