当使用Serde反序列化时,如何忽略额外的元组项?("trailing characters"错误)

11

Serde在将数据反序列化为常规结构体时会忽略未知的命名字段。当我将数据反序列化为元组结构体时(例如从异构的JSON数组中),如何忽略额外的项呢?

例如,以下代码可以很好地忽略额外的"c"字段:

#[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 }

相比之下,在元组中的额外项上会失败:

#[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 在反序列化时忽略多余的元组项是最简单的方法?

2个回答

9
您可以实现一个自定义的 Visitor,它会忽略序列中的其余部分。请注意,整个序列必须被消耗。这是一个重要的部分(试着将其删除,您将得到相同的错误):
// 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);
}

0

对于 JSON,我会结合 RawValue 和自定义反序列化:

use serde::{Deserialize, Deserializer};

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

#[derive(Deserialize, Debug)]
struct MyTupleFutureCompat<'a>(
    String,
    i32,
    #[serde(default, borrow)] Option<&'a serde_json::value::RawValue>,
);

impl<'de> Deserialize<'de> for MyTuple {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        let t: MyTupleFutureCompat = Deserialize::deserialize(deserializer)?;
        Ok(MyTuple(t.0, t.1))
    }
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let json = r#"[
        "foo",
        123,
        "ignore me"
    ]"#;
    let d: MyTuple = serde_json::from_str(json)?;
    println!("{:?}", d);
    Ok(())
}

另请参阅:


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