【问题标题】:How to ignore partial items of a sequence如何忽略序列的部分项目
【发布时间】:2019-12-19 11:04:46
【问题描述】:

不要将字段定义为可选字段,而是同时收集Nones 和Somes,如下所示:

extern crate serde;
extern crate serde_json;

use serde::Deserialize;

#[derive(Debug, Deserialize, PartialEq)]
struct Bar {
    a: u32,
    b: Option<u32>,
}

#[derive(Debug, Deserialize, PartialEq)]
struct Foo {
    vec: Vec<Bar>,
}

fn main() {
    let data = r#"{ "vec": [ { "a": 1 }, { "a": 2, "b": 3 } ] }"#;
    assert_eq!(
        serde_json::from_str::<Foo>(data).unwrap(),
        Foo {
            vec: vec![Bar { a: 1, b: None }, Bar { a: 2, b: Some(3) }]
        }
    );
}

最好只收集完全定义的元素,这样Bar 结构可以定义为struct Bar { a: u32, b: u32 }serde_json::from_str 将简单地返回Foo { vec: [ Bar { a: 2, b: 3 } ] }

如何实现这样的行为?这是我创建自定义Deserialize 实现以尝试解决此问题的失败尝试。

extern crate serde;
extern crate serde_json;

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

#[derive(Debug, Deserialize)]
struct Bar {
    a: i32,
    b: i32,
    c: i32,
}

#[derive(Debug)]
struct VecOpt(Vec<Bar>);

impl<'de> Deserialize<'de> for VecOpt {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        struct ArrayVecVisitor;

        impl<'de> Visitor<'de> for ArrayVecVisitor {
            type Value = VecOpt;

            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                write!(formatter, "VecOpt")
            }

            fn visit_seq<SA>(self, mut seq: SA) -> Result<Self::Value, SA::Error>
            where
                SA: SeqAccess<'de>,
            {
                let mut values = Vec::new();

                loop {
                    match seq.next_element::<Bar>() {
                        Ok(Some(x)) => values.push(x),
                        Ok(None) => break,
                        // If error, the input reader won't move to the next element of the sequence and the following `seq.next_element` will
                        // simply try to read contents of the current element. In this case, `"c": 5 }, ... `
                        Err(_) => {}
                    }
                }

                Ok(VecOpt(values))
            }
        }

        deserializer.deserialize_seq(ArrayVecVisitor)
    }
}

#[derive(Debug, Deserialize)]
struct Foo {
    vec: VecOpt,
}

fn main() {
    let data = r#"{ "vec": [ { "a": 1 "b": 2, "c": 3 }, { "b": 4, "c": 5 }, { "a": 6 "b": 7, "c": 8 } ] }"#;
    dbg!(serde_json::from_str::<Foo>(data).unwrap());
}

【问题讨论】:

  • 您的问题不包含实际问题或说明任何问题。
  • foo.vec.into_iter().filter_map(|b| Some(Baz { a: b.a, b: b.b? })).collect()?
  • @hellow 这会进行额外分配,我希望在反序列化时收集数据
  • 如果你在做collect,是的。

标签: rust deserialization serde


【解决方案1】:

您的代码在大部分情况下都可以正常工作,但 main 中的 JSON 文字无效,它错过了几个逗号,因此出错了。问题是Err(_) 分支不加选择地吞下了所有错误;它应该只消除丢失的字段错误:

fn visit_seq<SA>(self, mut seq: SA) -> Result<Self::Value, SA::Error>
where
    SA: SeqAccess<'de>,
{
    let mut values = Vec::new();

    loop {
        match seq.next_element::<Bar>() {
            Ok(Some(x)) => values.push(x),
            Ok(None) => break,
            Err(e) => {
                if !e.to_string().starts_with("missing field") {
                    return Err(e);
                }
            }
        }
    }

    Ok(VecOpt(values))
}

TBH 我真的不喜欢这个解决方案,尽管它有效。 Option 非常适合在这里对可能缺失的字段进行建模。

【讨论】:

  • 这是我个人不会使用的方法,但无论如何它是一个答案 =) 谢谢
猜你喜欢
  • 2019-11-19
  • 1970-01-01
  • 1970-01-01
  • 2014-07-18
  • 2016-01-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-27
相关资源
最近更新 更多