gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-11-29 07:43:49 24 4
gpt4 key购买 nike

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 在反序列化时忽略额外元组项的最简单方法是什么?

最佳答案

您可以实现一个忽略序列其余部分的自定义 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);
}

关于rust - 使用 Serde 反序列化时如何忽略额外的元组项? ("trailing characters"错误),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57529456/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com