请系好安全带,这是冗长的。
我假设你想反序列化一些 JSON 数据
{"x": [[1, "a"], [2, "b"]]}
到一些 Rust 结构
struct X {
x: Vec<Vec<Value>>, // Value is some enum containing string/int/float…
}
一直以来
- 在插入向量时转置内部列表的元素
- 检查内部向量元素是否符合传递给反序列化的某些类型
- 不做任何临时分配
一开始,您必须意识到您要反序列化三种不同的类型:X
、Vec<Vec<Value>>>
和Vec<Value>
. (Value
你不需要它本身,因为你真正想要反序列化的是字符串和整数等等,而不是Value
它本身。)所以,你需要三个反序列化器和三个访问者。
最内层Deserialize
有一个对 a 的可变引用Vec<Vec<Value>>
,并将单个 的元素分配[1, "a"]
给每个Vec<Value>
。
struct ExtendVecs<'a>(&'a mut Vec<Vec<Value>>, &'a [DataTypes]);
impl<'de, 'a> DeserializeSeed<'de> for ExtendVecs<'a> {
type Value = ();
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: Deserializer<'de>,
{
struct ExtendVecVisitor<'a>(&'a mut Vec<Vec<Value>>, &'a [DataTypes]);
impl<'de, 'a> Visitor<'de> for ExtendVecVisitor<'a> {
type Value = ();
fn visit_seq<A>(self, mut seq: A) -> Result<(), A::Error>
where
A: SeqAccess<'de>,
{
// Too short checks for None and turns it into Err("expected more elements")
for (i, typ) in self.1.iter().enumerate() {
match typ {
DataTypes::Stri => self.0[i].push(Value::Stri(too_short(self.1, seq.next_element::<String>())?)),
DataTypes::Numb => self.0[i].push(Value::Numb(too_short(self.1, seq.next_element::<f64>())?)),
}
}
// TODO: check all elements consumed
Ok(())
}
}
deserializer.deserialize_seq(ExtendVecVisitor(self.0, self.1))
}
}
中间Deserialize
构造Vec<Vec<Value>>
,提供对 的最里面的ExtendVecs
访问Vec<Vec<Value>>
,并要求ExtendVecs
查看每个[[…], […]]
:
struct TransposeVecs<'a>(&'a [DataTypes]);
impl<'de, 'a> DeserializeSeed<'de> for TransposeVecs<'a> {
type Value = Vec<Vec<Value>>;
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: Deserializer<'de>,
{
struct TransposeVecsVisitor<'a>(&'a [DataTypes]);
impl<'de, 'a> Visitor<'de> for TransposeVecsVisitor<'a> {
type Value = Vec<Vec<Value>>;
fn visit_seq<A>(self, mut seq: A) -> Result<Vec<Vec<Value>>, A::Error>
where
A: SeqAccess<'de>,
{
let mut vec = Vec::new();
vec.resize_with(self.0.len(), || vec![]);
while let Some(()) = seq.next_element_seed(ExtendVecs(&mut vec, self.0))? {}
Ok(vec)
}
}
Ok(deserializer.deserialize_seq(TransposeVecsVisitor(self.0))?)
}
}
最后,最外层Deserialize
不再有什么特别之处,它只是将访问类型数组的权限向下传递:
struct XD<'a>(&'a [DataTypes]);
impl<'de, 'a> DeserializeSeed<'de> for XD<'a> {
type Value = X;
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: Deserializer<'de>,
{
struct XV<'a>(&'a [DataTypes]);
impl<'de, 'a> Visitor<'de> for XV<'a> {
type Value = X;
fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
where
A: serde::de::MapAccess<'de>,
{
let k = map.next_key::<String>()?;
// TODO: check k = "x"
Ok(X { x: map.next_value_seed(TransposeVecs(self.0))? })
}
}
Ok(deserializer.deserialize_struct("X", &["x"], XV(self.0))?)
}
}
现在,您可以使用所需的类型列表播种最外层Deserialize
并使用它来反序列化 one X
,例如:
XD(&[DataTypes::Numb, DataTypes::Stri]).deserialize(
&mut serde_json::Deserializer::from_str(r#"{"x": [[1, "a"], [2, "b"]]}"#)
)
具有所有遗漏错误处理的游乐场
侧节点:如果可以(即,如果您要反序列化的格式是像 JSON 一样的自描述格式),我建议在反序列化后进行类型检查。为什么?因为在此期间执行此操作意味着所有反序列化器到顶部反序列化器都必须是DeserializeSeed
,并且您不能使用#[derive(Deserialize)]
. 如果你在之后进行类型检查,你可以#[derive(Deserialize)]
和#[serde(deserialize_with = "TransposeVecs_deserialize_as_free_function")} x: Vec<Vec<Value>>
, 并在这篇文章中节省一半的麻烦。