3

我有一个这样的类型,虽然我的实际类型更大更复杂:

struct MyType {
    i: u32,
}

如果我Deserialize为这种类型实现,serde 会寻找这样的东西(我对 JSON 感兴趣):

{"i":100}  

我想自定义它,以便我也可以从字节数组反序列化:

[1, 2, 3, 4]

我可以编写一个 impl 来处理数组,但我希望 serde 自动生成其余部分(将是visit_map):

impl<'de> Deserialize<'de> for MyType {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        struct MyTypeVisitor;

        impl<'de> Visitor<'de> for MyTypeVisitor {
            type Value = MyType;

            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                write!(formatter, "struct or array of 4 integers")
            }

            fn visit_seq<A: SeqAccess<'de>>(self, seq: A) -> Result<Self::Value, A::Error> {
                // ...
            }
        }

        // deserializer.deserialize_any(MyTypeVisitor)
    }
}

那可能吗?在这个例子中,这并不难,但是当结构体很大时,手写反序列化可能会很痛苦。

这不是如何在使用 Serde 反序列化期间转换字段的副本?因为deserialize_with仅适用于 1 个字段。我无法理解如何让它适用于我的真实类型:

pub enum Component {
    String(StringComponent),
    Translation(TranslationComponent),
    Score(ScoreComponent),
    Selector(SelectorComponent),
}

pub struct StringComponent {
    #[serde(flatten)] pub base: Base,
    pub text: String,
}

pub struct Base {
    // ...
    extra: Option<Vec<Component>>,
    // ...
}

我想做的是:

  • 反序列化时,如果输入是数字,则返回 a Component::String。这可以与visit_i//uf64朋友一起完成。
  • 如果输入是字符串,则Component::String再次返回 a。这可以用visit_str/来完成string
  • 如果输入是一个数组[..],像往常一样反序列化它,但是将数组[1..]中的元素分配给数组[0]的额外元素。这可以通过visit_seq.
  • 如果输入是一个地图,让 serde 派生处理它。
4

1 回答 1

1

Serde文档有一个示例,展示了如何从字符串或结构实现反序列化。这相当于你的情况,只是更小。

重要的部分是:

fn visit_map<M>(self, visitor: M) -> Result<T, M::Error>
where
    M: MapAccess<'de>,
{
    Deserialize::deserialize(de::value::MapAccessDeserializer::new(visitor))
}

这委托给内置的反序列化实现。由于您所有其他情况都是自定义的,因此这应该是合适的。

于 2018-03-28T17:29:31.733 回答