使用Serde反序列化时,如何忽略多余的元组项? (“尾随字符"错误) [英] How can I ignore extra tuple items when deserializing with Serde? ("trailing characters" error)

查看:151
本文介绍了使用Serde反序列化时,如何忽略多余的元组项? (“尾随字符"错误)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Serde在反序列化为常规结构时会忽略未知的命名字段.反序列化为元组结构时(例如,从异构JSON数组中),我如何类似地忽略多余的项目?

Serde ignores unknown named fields when deserializing into regular structs. How can I similarly ignore extra items when deserializing into tuple structs (e.g. from a heterogeneous JSON array)?

例如,此代码忽略了多余的"c"字段:

For example, this code ignores the extra "c" field just fine:

#[derive(Serialize, Deserialize, Debug)]
pub struct MyStruct { a: String, b: i32 }

fn test_deserialize() -> MyStruct {
    ::serde_json::from_str::<MyStruct>(r#"
    {
        "a": "foo",
        "b": 123,
        "c": "ignore me"
    }
    "#).unwrap()
}
// => MyStruct { a: "foo", b: 123 }

相比之下,这在元组中的多余项上失败:

By contrast, this fails on the extra item in the tuple:

#[derive(Serialize, Deserialize, Debug)]
pub struct MyTuple(String, i32);

fn test_deserialize_tuple() -> MyTuple {
    ::serde_json::from_str::<MyTuple>(r#"
        [
            "foo",
            123,
            "ignore me"
        ]
    "#).unwrap()
}
// => Error("trailing characters", line: 5, column: 13)

我想允许额外的项目以我的数据格式向前兼容.使Serde在反序列化时忽略多余的元组项的最简单方法是什么?

I'd like to allow extra items for forward compatibility in my data format. What's the easiest way to get Serde to ignore extra tuple items when deserializing?

推荐答案

您可以实现一个自定义的Visitor,它忽略其余序列.请注意,必须消耗整个序列.这是重要的部分(尝试将其删除,您将得到相同的错误):

You can implement a custom Visitor which ignores rest of the sequence. Be aware that the whole sequence must be consumed. This is an important part (try to remove it and you'll get same error):

// This is very important!
while let Some(IgnoredAny) = seq.next_element()? {
    // Ignore rest
}

这是一个可行的示例:

use std::fmt;

use serde::de::{self, Deserialize, Deserializer, IgnoredAny, SeqAccess, Visitor};
use serde::Serialize;

#[derive(Serialize, Debug)]
pub struct MyTuple(String, i32);

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

        impl<'de> Visitor<'de> for MyTupleVisitor {
            type Value = MyTuple;

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

            fn visit_seq<V>(self, mut seq: V) -> Result<Self::Value, V::Error>
            where
                V: SeqAccess<'de>,
            {
                let s = seq
                    .next_element()?
                    .ok_or_else(|| de::Error::invalid_length(0, &self))?;
                let n = seq
                    .next_element()?
                    .ok_or_else(|| de::Error::invalid_length(1, &self))?;

                // This is very important!
                while let Some(IgnoredAny) = seq.next_element()? {
                    // Ignore rest
                }

                Ok(MyTuple(s, n))
            }
        }

        deserializer.deserialize_seq(MyTupleVisitor)
    }
}

fn main() {
    let two_elements = r#"["foo", 123]"#;
    let three_elements = r#"["foo", 123, "bar"]"#;

    let tuple: MyTuple = serde_json::from_str(two_elements).unwrap();
    assert_eq!(tuple.0, "foo");
    assert_eq!(tuple.1, 123);

    let tuple: MyTuple = serde_json::from_str(three_elements).unwrap();
    assert_eq!(tuple.0, "foo");
    assert_eq!(tuple.1, 123);
}

这篇关于使用Serde反序列化时,如何忽略多余的元组项? (“尾随字符"错误)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆