实现 Deserialize

Deserialize trait 如下所示:

use serde::Deserializer;

pub trait Deserialize<'de>: Sized {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>;
}

fn main() {}

这个方法的作用是通过为 Deserializer 提供一个 Visitor,将类型映射到 Serde 数据模型,然后由 Deserializer 驱动 Visitor 来构建类型的实例。

在大多数情况下,Serde 的 derive 能够为您的 crate 中定义的 struct 和 enum 生成适当的 Deserialize 实现。如果您需要对某种类型的反序列化行为进行自定义,而派生不支持该行为,可以自己实现 Deserialize。实现 Deserialize 对于类型而言比实现Serialize 更加复杂。

Deserializer trait 支持两种入口样式,从而实现不同种类的反序列化。

  1. deserialize_any 方法。像 JSON 这样的自描述数据格式能够查看序列化数据并判断其代表的内容。例如,JSON 反序列化器可能看到一个左花括号 ({) 并知道它看到的是一个 map。如果数据格式支持 Deserializer::deserialize_any,它将根据 input 中判断的类型来驱动 Visitor。JSON 在反序列化 serde_json::Value 时使用了这种方法,它是能够表示任何 JSON 文档的 enum。不需要知道 JSON 文档中的内容是什么,我们也可以通过 Deserializer::deserialize_any 将其反序列化为 serde_json::Value

  2. 其他各种 deserialize_* 方法。非自描述格式例如 Postcard 需要告诉输入中包含的是什么内容才能对其进行反序列化。deserialize_* 方法是为反序列器提供关于如何解释下一个输入片段的提示。非自描述格式无法对类似serde_json::Value 这样依赖 Deserializer::deserialize_any 的内容进行反序列化。

在实现 Deserialize 时,应避免依赖Deserializer::deserialize_any,除非需要反序列化器告诉您输入中的类型。要知道,依赖Deserializer::deserialize_any 意味着您的数据类型只能从自描述格式中反序列化,排除了 Postcard 等许多其他格式。

The Visitor trait

Visitor 是由 Deserialize 实例化并传递给 Deserializer 的。然后,Deserializer 会调用 Visitor 上的方法来构造所需类型。

这是一个 Visitor 示例,能够从各种类型中反序列化基本的 i32

use std::fmt;

use serde::de::{self, Visitor};

#[allow(dead_code)]
struct I32Visitor;

impl<'de> Visitor<'de> for I32Visitor {
    type Value = i32;

    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_str("an integer between -2^31 and 2^31")
    }

    fn visit_i8<E>(self, value: i8) -> Result<Self::Value, E>
    where
        E: de::Error,
    {
        Ok(i32::from(value))
    }

    fn visit_i32<E>(self, value: i32) -> Result<Self::Value, E>
    where
        E: de::Error,
    {
        Ok(value)
    }

    fn visit_i64<E>(self, value: i64) -> Result<Self::Value, E>
    where
        E: de::Error,
    {
        use std::i32;
        if value >= i64::from(i32::MIN) && value <= i64::from(i32::MAX) {
            Ok(value as i32)
        } else {
            Err(E::custom(format!("i32 out of range: {}", value)))
        }
    }

    // 其他方法类似:
    //   - visit_i16
    //   - visit_u8
    //   - visit_u16
    //   - visit_u32
    //   - visit_u64
}

fn main() {}

Visitor trait 还有许多没有为I32Visitor实现的方法。如果调用这些方法,将返回类型错误。例如,I32Visitor没有实现Visitor::visit_map,因此尝试在输入包含映射时反序列化一个i32 是一个类型错误。

驱动 Visitor

通过向给定的 Deserializer 传递一个 Visitor 来反序列化值。Deserializer 将根据输入数据之间调用 Visitor 的某个方法,这称为 “驱动” Visitor

use std::fmt;

use serde::de::{Deserialize, Deserializer, Visitor};

#[allow(non_camel_case_types)]
struct i32;
struct I32Visitor;

impl<'de> Visitor<'de> for I32Visitor {
    type Value = i32;

    fn expecting(&self, _: &mut fmt::Formatter) -> fmt::Result {
        unimplemented!()
    }
}

impl<'de> Deserialize<'de> for i32 {
    fn deserialize<D>(deserializer: D) -> Result<i32, D::Error>
    where
        D: Deserializer<'de>,
    {
        deserializer.deserialize_i32(I32Visitor)
    }
}

fn main() {}

请注意,Deserializer 不一定会遵循类型提示,因此调用 deserialize_i32并不一定意味着 Deserializer 将调用 I32Visitor::visit_i32。例如,JSON 将所有有符号整数类型视为相同。JSON Deserializer 将对任何有符号整数调用 visit_i64,对任何无符号整数调用 visit_u64,即使提示不同的类型也是如此。

其他示例