2

我正在编写一个库来解析如下所示的 json 数据:

{"x": [[1, "a"], [2, "b"]]}

即我有一个带有列表列表的键,其中内部列表可以包含不同的数据类型,但每个内部列表具有相同的类型序列。内部列表的类型序列可以针对不同的 json 模式而改变,但会提前知道。

所需的输出看起来像:( vec![vec![1,2], vec!["a", "b"]] 将数据包装在针对不同 dtype 的一些适当的枚举中)。

我开始实现DeserializeSeedfor Vec<DataTypes>,下面是一些类似的伪代码。

enum DataTypes {
    I32,
    I64,
    String,
    F32,
    F64
}


fn visit_seq<S>(self, mut seq: S) -> Result<Self::Value, S::Error>
    where
        S: SeqAccess<'de>,
    {
        let types: Vec<DataTypes> = self.0.data;
        let out: Vec<Vec<...>>;
        while let Some(inner_seq: S) = seq.next_element::<S>()? { // <-- this is the line
           for (i, type) in types.enumerate() {
               match type {
                   DataTypes::I32 => out[i].push(inner_seq.next_element::<i32>()?),
                   DataTypes::I64 => out[i].push(inner_seq.next_element::<i64>()?),
                   ...
               }
           }
        }
    }

我的问题是我似乎找不到为内部列表获取 SeqAccess 的方法,我不想将它们反序列化为类似的东西,Vec<serde_json::Value>因为我不想分配额外的向量。

4

1 回答 1

3

请系好安全带,这是冗长的。

我假设你想反序列化一些 JSON 数据

{"x": [[1, "a"], [2, "b"]]}

到一些 Rust 结构

struct X {
    x: Vec<Vec<Value>>, // Value is some enum containing string/int/float…
}

一直以来

  • 在插入向量时转置内部列表的元素
  • 检查内部向量元素是否符合传递给反序列化的某些类型
  • 不做任何临时分配

一开始,您必须意识到您要反序列化三种不同的类型:XVec<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>>, 并在这篇文章中节省一半的麻烦。

于 2022-03-03T06:37:09.260 回答