rust - 使用 Serde 反序列化时如何忽略额外的元组项?(“尾随字符”错误)
问题描述
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);
}
推荐阅读
- ios - 无法获取关注者计数 GetStream Swift
- android - 电话。不。登录在android中工作,但数据也没有存储在服务器和api上
- javascript - Visual Studio Code - 如何在调试期间内联显示变量值?
- service - 无法创建 Ingress
- azure - AzureAD SAML ACS URL 接受用于本地开发目的的 HTTP 端点
- python - Python:如何从列中找到唯一日期的计数
- java - 我在使用 jcraft-Jsch api 执行 java 文件传输程序但使用其他 API 时收到 java.net.SocketTimeoutException
- xcode - 如何修复 Flutter Xcode 项目中的 Bundle Identifier?
- tensorflow - Tensorflow 2.0:如何将随机序列传递给解码器输入
- javascript - Reactjs 中的侧边栏和导航。在渲染组件内路由