实现serde序列化的Serialize trait

203 阅读4分钟

前面我们已经介绍了serde的序列化和反序列化的一些知识,从怎么使用SerializeDeserialize以及把属性分为容器属性,变量属性,以及字段属性。那么我们如果我们想要更加灵活,根据自己的实际情况来序列化或者反序列化的时候该怎么办呢,这就是我们接下来的目的。刚好色的允许通过手动为我们自己的类型实现SerializeDeserialize traits 来完全定制序列化行为。

我们先看在Serde框架中关于SerializeDeserialize traits的定义:

pub trait Serialize {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer;
}

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

实现Serialize trait

上面我们已经贴出了Serialize的定义了,里面的deserialize方法的作用就是取出你的类型(&self),通过在给定的Serialize上恰当的一个方法来映射它到Serde数据模型

在大多数情况官方的基本上能满足你的需求,但是在实际开发过程中根据自身需求需要自定义某种类型的序列化行为,而派生不支持,那么你就可以自己实现Serialize trait序列化你的数据结构。

序列化基本类型

我们先来个最经典的也最简单的例子,我们以i32为例:

impl Serialize for i32{
  fn serialize<S>(&self,serializer:S) -> Result<S::Ok,S::Error> where 
  S:Serializer,{
     serializer.serialize_i32(*self)
  }
}

Serde为所有Rust的基本类型提供了类似上面i32的实现,因此我们不需要吃力不讨好的再去实现它们。

序列化sequence或map

复合类型遵循初始化(init),元素(element),结束(end)的三步过程。

 use serde::ser::{Serialize,Serializer,SerializeSeq, SerializeMap}
 impl<T> Serialize for Vec<T> where T:Serialize{
   let mut seq = serializer.serialize_seq(Some(self.len()))?;
   for e in self{
     seq.serialize_element(e)?;
   }
   seq.end()
 }
 
 impl <K,V> Serialize for MyMap<K,V>
 where K:Serialize,
       V:Serialize,
      {
         fn serialize<S>(&self,serilizer:S) ->Result<S::Ok,S::Error>
         where S:Serilizer,
         {
            let mut map = serializer.serialize_map(Some(self.len()))?;
            for (k,v) in self{
              map.serialize_entry(k,v)?;
            }
            map.end()
         }
      }

序列化struct

Serde区分四种类型的结构体。普通结构体和元祖结构体遵循初始化,元素,结束三步骤过程。就像sequence或map一样。新类型结构体和单元结构体更像基本类型。

// 一个普通结构体。使用三步过程
//     1. serialize_struct
//     2. serialize_field
//     3. end
struct Color{
  r:u8,
  g:u8,
  b:u8,
}


// 一个元祖结构体。使用三步过程。
//    1. seialize_tuple_struct
//    2. serialize_field
//    3. end
struct Point3D(f64,f64,f64);

// 一个新类型结构体。使用serialize_newtype_strcut
struct Inches(u64);

// 一个单元结构体。使用serialize_unit_struct
struct Instance;

有时候我们傻傻的分不清JSON,struct和map可能看起来查不多,分不清李逵还是李鬼。那么Serde区别他们在于struct具有在编译时常量的字符串键,并且这些键在不查看序列化的情况下是已知的。这个条件使得某些数据格式化能够比map更高效和更紧凑地处理struct.

use serde::ser::{Serialize, Serializer, SerializeStruct};

struct Color {
    r: u8,
    g: u8,
    b: u8,
}

impl Serialize for Color {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        // 3 是结构体中字段的数量。
        let mut state = serializer.serialize_struct("Color"3)?;
        state.serialize_field("r", &self.r)?;
        state.serialize_field("g", &self.g)?;
        state.serialize_field("b", &self.b)?;
        state.end()
    }
}

序列化enum

序列化enum variants与序列化struct相似

enum E{
  // 使用三步过程:
  //  1. serialize_struct_variant
  //  2. serialize_field
  //  3.end
  Color{ r:u8,g:u8,b:u8},
  
  // 使用三步过程:
  //  1. serialize_tuple_variant
  //  2. serialize_field
  //  3. end
  Point3D(f64,f64,f64)
  
  // 使用 serialize_newtype_variant
  Inches(u64)
  
  // 使用 serialize_unit_variant
  Instance
}

其它的一些情况

有两个更特殊的情况,属于 Serializer trait 的一部分。

有一个方法 serialize_bytes,用于序列化 ``&[u8]。有些格式将bytes视为seq,但有些格式能够更紧凑地序列化bytes。目前,Serde 在Serialize实现中不使用serialize_bytes用于&[u8]Vec,但一旦specialization在稳定的 Rust 中出现,我们将开始使用它。目前可以使用serde_bytes crate` 来使得能够通过 serialize_bytes 高效处理 &[u8] 和 Vec。

最后,serialize_some 和 serialize_none 对应于 Option::Some 和 Option::None。用户对 Option 枚举的期望通常与其他枚举不同。Serde JSON 将 Option::None 序列化为 null,将 Option::Some 仅序列化为包含的值。

请大家多多关注我的公众号:花说编程