Serde在反序列化为常规 struct 时忽略未知的命名字段.在反序列化为元组 struct (例如,从异类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忽略额外元组项的最简单方法是什么?

推荐答案

您可以实现一个自定义Visitor,忽略序列的其余部分.请注意,必须使用整个序列.这是一个重要的部分(try 删除它,你会得到同样的错误):

// 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);
}

Rust相关问答推荐

为什么实例化核心::time::ns不安全?

为什么我们不能通过指针算法将Rust原始指针指向任意地址?'

如何在Rust中表示仅具有特定大小的数组

具有对同一类型的另一个实例的可变引用的

修改切片/引用数组

你是如何在铁 rust 一侧的金牛座获得应用程序版本的?

将PathBuf转换为字符串

我是否可以在Ruust中修改 struct 实例上的字符串,以使其在修改后具有相同的字符串生存期?

有没有可能让泛型Rust T总是堆分配的?

为什么比较Option<;字符串>;具有常数Option<&;str>;需要显式类型转换吗?

Google chrome 和 Apple M1 中的计算着色器

Rust中如何实现一个与Sized相反的负特性(Unsized)

Rust 打包在 .deb 中

按下 Ctrl + C 时优雅地停止命令并退出进程

为什么要这样编译?

在 Rust 中使用 `SecTrustSettingsSetTrustSettings` 绑定导致 `errSecInternalComponent`

为什么 Rust 允许写入不可变的 RwLock?

为什么会出现无法移出可变引用后面的 `self.x`错误?

tokio async rust 的 yield 是什么意思?

在 Rust 中枚举字符串的最佳方式? (字符()与 as_bytes())