Serde是一个用于高效、通用的对 Rust 数据结构进行序列化和反序列化框架,也是 Rust 程序开发过程中最常用的库之一。

不同于其他变成语言需要依赖运行时或者反射来对数据进行序列化,Serde 则是建立的 Rust 强大的 Trait 系统之上,让我们能够写出更加高效的序列化、反序列化代码。

目前 Serde 生态非常丰富,已经支持很多类型,包括我们常见的 json 、 Yaml 、 Toml 、 Csv 、 Bson 等,还有其他的比如 URL 、 MessagePack 等。

快速入门

我们以 json 为例,为了让我们的数据结构能够支持序列化和反序列化,需要引入 serde 依赖。

命令行添加:

# 添加serde依赖
cargo add serde --features derive
# 添加支持 json 的依赖
cargo add serde_json

您也可以直接编辑 Cargo.toml,添加以下内容:

[dependencies]
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"

假如代码如下:

use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize, Debug)]
struct Point {
    x: i32,
    y: i32,
}

fn main() {
    let point = Point { x: 1, y: 2 };

    let serialized = serde_json::to_string(&point).unwrap();
    // 输出结果: serialized = {"x":1,"y":2}
    println!("serialized = {}", serialized);

    let deserialized: Point = serde_json::from_str(&serialized).unwrap();
    // 输出结果: deserialized = Point { x: 1, y: 2 }
    println!("deserialized = {:?}", deserialized);
}

文件中我们在结构体 Point上面添加了 #[derive(Serialize, Deserialize, Debug)],三个 derive 分别代表:

  • Serialize: 为结构体添加序列化支持
  • Deserialize: 为架构体添加反序列化支持
  • Debug: 这个与 Serde 无关,平时很常见,添加 Debug 输出支持。

属性说明

Serde支持大量的属性配置,用来实现更多自定义的序列化、反序列化配置。这些属性需要 Rust 编译器版本在1.15或以上。

Serde 的属性主要有三类:

  • 容器属性: 主要应用于struct 和 enum 上的声明
  • 变体属性: 主要在 enum 的各种变体上声明
  • 字段属性:主要在 struct 或者 enum 变体的字段上声明
#[derive(Serialize, Deserialize)]
#[serde(deny_unknown_fields)] // <-- 这是一个容器属性
struct S {
    #[serde(default)] // <-- 这是一个字段属性
    f: i32,
}

#[derive(Serialize, Deserialize)]
#[serde(rename = "e")] // <-- 这还是一个容器属性
enum E {
    #[serde(rename = "a")] // <-- 这是一个变体属性
    A(String),
}

请注意,单个结构体、枚举体、变体或者字段可能会同时具备多个属性。

容器属性

#[serde(rename = "name")]

使用给定的名字进行序列化或者反序列化,而不是使用 Rust 结构内的名字。同时允许我们为序列化或反序列化指定单独的名称。

  • #[serde(rename(serialize = "ser_name"))]
  • #[serde(rename(deserialize = "de_name"))]
  • #[serde(rename(serialize = "ser_name", deserialize = "de_name"))]

#[serde(rename_all = "...")]

重命名所有的字段(如果是结构体)或变体(如果是枚举体)。可能的值有 "lowercase", "UPPERCASE", "PascalCase", "camelCase", "snake_case", "SCREAMING_SNAKE_CASE", "kebab-case", "SCREAMING-KEBAB-CASE"。

我们也可以为序列化、反序列化单独指定规则:

  • #[serde(rename_all(serialize = "..."))]
  • #[serde(rename_all(deserialize = "..."))]
  • #[serde(rename_all(serialize = "...", deserialize = "..."))]

示例:

use serde::{Deserialize, Serialize};

#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "UPPERCASE")]
struct User {
    name: String,
    age: u8,
    sex: Sex,
}

#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
enum Sex {
    Male,    // 男性
    FeMale,  // 女性
    Unknown, // 未知
}

fn main() {
    let user = User {
        name: "Tom".to_string(),
        age: 20,
        sex: Sex::Male,
    };

    let serialized = serde_json::to_string(&user).unwrap();
    // 输出结果: serialized = {"NAME":"Tom","AGE":20,"SEX":"MALE"}
    println!("serialized = {}", serialized);

    let deserialized: User = serde_json::from_str(&serialized).unwrap();
    // 输出结果: deserialized = User { name: "Tom", age: 20, sex: Male }
    println!("deserialized = {:?}", deserialized);
}

#[serde(rename_all_fields = "...")]

对 enum 变体中的结构体字段进行重命名,可支持的值有 "lowercase", "UPPERCASE", "PascalCase", "camelCase", "snake_case", "SCREAMING_SNAKE_CASE", "kebab-case", "SCREAMING-KEBAB-CASE"。

我们也可以为序列化、反序列化单独指定规则:

  • #[serde(rename_all_fields(serialize = "..."))]
  • #[serde(rename_all_fields(deserialize = "..."))]
  • #[serde(rename_all_fields(serialize = "...", deserialize = "..."))]

示例:

use serde::{Deserialize, Serialize};

#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all_fields = "UPPERCASE")]
enum Car {
    Benz { model: String, price: f64 },
    BMW { model: String, price: f64 },
    Audi { model: String, price: f64 },
}

fn main() {
    let car = Car::Benz {
        model: "S500".to_string(),
        price: 100.0,
    };
    let serialized = serde_json::to_string(&car).unwrap();
    // 输出结果: serialized = {"Benz":{"MODEL":"S500","PRICE":100.0}}
    println!("serialized = {}", serialized);

    let deserialized: Car = serde_json::from_str(&serialized).unwrap();
    // 输出结果: deserialized = Benz { model: "S500", price: 100.0 }
    println!("deserialized = {:?}", deserialized);
}

#[serde(deny_unknown_fields)]

在反序列化时,遇到未知字段会报错。当这个属性不存在时,默认情况下,遇到未知字段将会被忽略。

注意这个属性不能和flatten一起使用,不管是在外部结构或者展开后的结构上面。

use serde::{Deserialize, Serialize};

#[derive(Debug, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
struct Point {
    x: i32,
    y: i32,
}

fn main() {
    let point = Point { x: 1, y: 2 };

    let serialized = serde_json::to_string(&point).unwrap();
    // 输出结果: serialized = {"x":1,"y":2}
    println!("serialized = {}", serialized);

    let deserialized: Point = serde_json::from_str(&serialized).unwrap();
    // 输出结果: deserialized = Point { x: 1, y: 2 }
    println!("deserialized = {:?}", deserialized);

    let json = r#"{"x":1,"y":2, "z": 3}"#;
    let deserialized_json: Point = serde_json::from_str(&json).unwrap();
    // 会报错:called `Result::unwrap()` on an `Err` value: Error("unknown field `z`, expected `x` or `y`", line: 1, column: 17)
    println!("deserialized_json = {:?}", deserialized_json);
}

由于我们为Point添加了#[serde(deny_unknown_fields)]属性,而最后的 json 中有一个字段z在 Point 中并不存在,所以报错,提示 unknown field z

#[serde(tag = "type")]

在 enum 上:使用内部标记的枚举表示,带有给定的标记。

在具名结构体上:在结构体所有的实际字段之前,将结构体的名称(或者是serde(rename)的值)序列化为指定的 key 。

示例1:对于具名结构体,只添加tag参数,会在 json 中添加tag对应的只为 key,struct 的类型为 value 的字段。

use serde::{Deserialize, Serialize};

#[derive(Debug, Serialize, Deserialize)]
#[serde(tag = "type")]
struct Point {
    x: i32,
    y: i32,
}

fn main() {
    let point = Point { x: 1, y: 2 };

    let serialized = serde_json::to_string(&point).unwrap();
    // 输出结果: serialized = {"type":"Point","x":1,"y":2}
    println!("serialized = {}", serialized);
}

示例2:对于具名结构体,当我们同时添加tagrename,序列化结果中会增加以tag值为 key,以rename值为 value 的新字段。

use serde::{Deserialize, Serialize};

#[derive(Debug, Serialize, Deserialize)]
#[serde(tag = "type", rename = "PointType")]
struct Point {
    x: i32,
    y: i32,
}

fn main() {
    let point = Point { x: 1, y: 2 };

    let serialized = serde_json::to_string(&point).unwrap();
    // 输出结果: serialized = {"type":"PointType","x":1,"y":2}
    println!("serialized = {}", serialized);
}

示例3: 对于一个 enum,会增加tag值为key,变体类型为值的新 key 。

use serde::{Deserialize, Serialize};

#[derive(Debug, Serialize, Deserialize)]
#[serde(tag = "type")]
enum Sex {
    Male,    // 男性
    FeMale,  // 女性
    Unknown, // 未知
}

fn main() {
    let sex = Sex::FeMale;

    let serialized = serde_json::to_string(&sex).unwrap();
    // 输出结果: serialized = {"type":"FeMale"}
    println!("serialized = {}", serialized);
}

#[serde(tag = "t", content = "c")]

用于 enum 类型, 会把对应变体关联的信息也序列化到content指定的字段内。

示例:

use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize)]
#[serde(tag = "t", content = "c")]
enum DataType {
    VecU8(Vec<u8>),
    Str(String),
    Struct { id: u32, name: String },
}

fn main() {
    let data1 = DataType::VecU8(vec![1, 2, 3]);

    let serialized = serde_json::to_string(&data1).unwrap();
    // 输出结果: serialized = {"t":"VecU8","c":[1,2,3]}
    println!("serialized = {}", serialized);

    let data = DataType::Str("Hello".to_string());
    let serialized = serde_json::to_string(&data).unwrap();
    // 输出结果: serialized = {"t":"Str","c":"Hello"}
    println!("serialized = {}", serialized);

    let data = DataType::Struct {
        id: 1,
        name: "Tom".to_string(),
    };
    let serialized = serde_json::to_string(&data).unwrap();
    // 输出结果: serialized = {"t":"Struct","c":{"id":1,"name":"Tom"}}
    println!("serialized = {}", serialized);
}

#[serde(untagged)]

也是用于 enum 类型,不会对内容进行任何标记字段包裹。

示例:

use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize)]
#[serde(untagged)]
enum DataType {
    VecU8(Vec<u8>),
    Str(String),
    Struct { id: u32, name: String },
}

fn main() {
    let data1 = DataType::VecU8(vec![1, 2, 3]);

    let serialized = serde_json::to_string(&data1).unwrap();
    // 输出结果: serialized = [1,2,3]
    println!("serialized = {}", serialized);

    let data = DataType::Str("Hello".to_string());
    let serialized = serde_json::to_string(&data).unwrap();
    // 输出结果: serialized = "Hello"
    println!("serialized = {}", serialized);

    let data = DataType::Struct {
        id: 1,
        name: "Tom".to_string(),
    };
    let serialized = serde_json::to_string(&data).unwrap();
    // 输出结果: serialized = {"id":1,"name":"Tom"}
    println!("serialized = {}", serialized);
}

#[serde(bound = "T: MyTrait")]

SerializeDeserialize实现的 where 子句。会替换 Serde 推断类型时的任何 Trait 。

允许为序列化和反序列化单独指定。

  • #[serde(bound(serialize = "T: MySerTrait"))]
  • #[serde(bound(deserialize = "T: MyDeTrait"))]
  • #[serde(bound(serialize = "T: MySerTrait", deserialize = "T: MyDeTrait"))]

???

#[serde(default)]

反序列化时,从结构的 Default 实现中 填写所有缺少的字段。

示例:

use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize, Debug, Default)]
#[serde(default)]
struct Point {
    x: i32,
    y: i32,
}

fn main() {
    let json = r#"{"x": 1}"#;
    let point: Point = serde_json::from_str(json).unwrap();
    // 输出结果: point = Point { x: 1, y: 0 }
    println!("point = {:?}", point);
}

虽然我们的 json 中没有字段y,但是犹豫我们添加了#[serde(default)],反序列化会为我们添加默认值。

#[serde(default = "path")]

反序列化时,使用给定函数或方法返回的对象中填写所有缺少的字段。该函数声明为 fn() -> T

例如,default="my_default"将调用 my_default(),而 default = "SomeTrait::some_default" 将调用SomeTrait::some_default()

示例:

use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize, Debug, Default)]
#[serde(default = "Point::default_value")]
struct Point {
    x: i32,
    y: i32,
}

impl Point {
    fn default_value() -> Self {
        Point { x: 2, y: 2 }
    }
}

fn main() {
    let json = r#"{"x": 1}"#;
    let point: Point = serde_json::from_str(json).unwrap();
    // 输出结果: point = Point { x: 1, y: 2 }
    println!("point = {:?}", point);
}

#[serde(remote = "...")]

用于远程类型派生SerializeDeserialize

???

#[serde(transparent)]

主要用于 newtype 类型结构体,或者只有一个字段的结构体,可以去除字段名的包裹。

示例:

use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize, Debug)]
struct UserId {
    value: String,
}

#[derive(Serialize, Deserialize, Debug)]
#[serde(transparent)]
struct UserId1 {
    value: String,
}

fn main() {
    let s = UserId {
        value: "hello".to_string(),
    };
    let serialized = serde_json::to_string(&s).unwrap();
    // 输出结果: serialized = {"value":"hello"}
    println!("serialized = {}", serialized);

    let s1 = UserId1 {
        value: "hello".to_string(),
    };
    let serialized1 = serde_json::to_string(&s1).unwrap();
    // 输出结果: serialized1 = "hello"
    println!("serialized1 = {}", serialized1);
}

#[serde(from = "FromType")]

通过反序列化为FromType,然后转换来反序列化此类型。此类型必须实现From<FromType>,而FromType必须实现Deserialize

示例:

use serde::{Deserialize, Serialize};
use std::convert::From;

#[derive(Debug, Serialize, Deserialize)]
#[serde(from = "RgbColor")]
enum Color {
    Rgb(u8, u8, u8),
}

#[derive(Debug, Serialize, Deserialize)]
struct RgbColor {
    r: u8,
    g: u8,
    b: u8,
}

impl From<RgbColor> for Color {
    fn from(rgb: RgbColor) -> Self {
        Color::Rgb(rgb.r, rgb.g, rgb.b)
    }
}

fn main() {
    let data_str = r#"{"r":128,"g":128,"b":128}"#;
    let color: Color = serde_json::from_str(&data_str).unwrap();
    // 输出结果: color = Rgb(128, 128, 128)
    println!("color = {:?}", color);
}

#[serde(try_from = "FromType")]

通过反序列化为FromType,然后转换来反序列化此类型。此类型必须实现TryFrom<FromType>,而FromType必须实现Deserialize

示例:

use serde::{Deserialize, Serialize};
use std::convert::TryFrom;

#[derive(Debug, Serialize, Deserialize)]
#[serde(try_from = "RgbColor")]
enum Color {
    Rgb(u8, u8, u8),
}

#[derive(Debug, Serialize, Deserialize)]
struct RgbColor {
    r: u8,
    g: u8,
    b: u8,
}

impl TryFrom<RgbColor> for Color {
    type Error = String;

    fn try_from(rgb: RgbColor) -> Result<Self, Self::Error> {
        Ok(Color::Rgb(rgb.r, rgb.g, rgb.b))
    }
}

fn main() {
    let data_str = r#"{"r":128,"g":128,"b":128}"#;
    let color: Color = serde_json::from_str(&data_str).unwrap();
    // 输出结果: color = Rgb(128, 128, 128)
    println!("color = {:?}", color);
}

#[serde(into = "IntoType")]

序列化之前,现将该类型转换为 IntoType 类型,然后再序列化。此类型必须实现 CloneInto<IntoType>, 且 IntoType 必须实现 Serialize

示例:

use serde::{Deserialize, Serialize};

#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(into = "RgbColor")]
enum Color {
    Rgb(u8, u8, u8),
}

#[derive(Debug, Serialize, Deserialize)]
struct RgbColor {
    r: u8,
    g: u8,
    b: u8,
}

impl Into<RgbColor> for Color {
    fn into(self) -> RgbColor {
        match self {
            Color::Rgb(r, g, b) => RgbColor { r, g, b },
        }
    }
}

fn main() {
    let color = Color::Rgb(30, 30, 30);
    let serialized = serde_json::to_string(&color).unwrap();
    // 输出结果: serialized = {"r":30,"g":30,"b":30}
    println!("serialized = {}", serialized);
}

#[serde(crate = "...")]

指定从生成的代码中,引用 Serde API 时,要使用的 Serde crate实例的路径。这通常仅适用于从不同 crate 中的公共宏调用重新导出的Serde。

???

#[serde(expecting = "...")]

为反序列化错误消息指定自定义类型期望文本。这由容器Visitor的生成expecting方法使用,并作为未标记枚举的故障消息。

变体属性

#[serde(rename = "name")]

使用给定名称而不是其Rust名称序列化和反序列化此变体。

允许为序列化与反序列化指定独立名称:

  • #[serde(rename(serialize = "ser_name"))]
  • #[serde(rename(deserialize = "de_name"))]
  • #[serde(rename(serialize = "ser_name", deserialize = "de_name"))]

#[serde(alias = "name")]

从给定名称或其Rust名称反序列化此变体。可以重复为同一变体指定多个可能的名称。

#[serde(rename_all = "...")]

根据给定的规则约定重命名此结构变体的所有字段。

可支持的值有"lowercase", "UPPERCASE", "PascalCase", "camelCase", "snake_case", "SCREAMING_SNAKE_CASE", "kebab-case", "SCREAMING-KEBAB-CASE"。

允许为序列化与反序列化指定独立重命名规则:

  • #[serde(rename_all(serialize = "..."))]
  • #[serde(rename_all(deserialize = "..."))]
  • #[serde(rename_all(serialize = "...", deserialize = "..."))]

#[serde(skip)]

序列化或者反序列化时跳过该变体。

#[serde(skip_serializing)]

序列化时跳过该变体。尝试序列化此变体将报错。

#[serde(skip_deserializing)]

反序列化时跳过该变体。

#[serde(serialize_with = "path")]

使用与其Serialize实现不同的函数序列化此变体。提供的函数声明需要是fn<S>(&FIELD0, &FIELD1, ..., S) -> Result<S::Ok, S::Error> where S: Serializer。尽管它也可能是FIELD{n}类型的泛型。与serialize_with一起使用的变体不需要能够派生Serialize

FIELD{n}存在于变体的每个字段中。因此,单元变体只有S参数,元组/结构体变体每个字段都有一个参数。

use serde::{Deserialize, Serialize, Serializer};

#[derive(Debug, Serialize, Deserialize)]
enum Color {
    #[serde(serialize_with = "serialize_rgb")]
    Rgb(u8, u8, u8),
}

#[derive(Debug, Serialize, Deserialize)]
struct RgbColor {
    r: u8,
    g: u8,
    b: u8,
}

fn serialize_rgb<S>(r: &u8, g: &u8, b: &u8, serializer: S) -> Result<S::Ok, S::Error>
where
    S: Serializer,
{
    let color = RgbColor {
        r: *r,
        g: *g,
        b: *b,
    };
    color.serialize(serializer)
}

fn main() {
    let data = Color::Rgb(30, 30, 30);
    let serialized = serde_json::to_string(&data).unwrap();
    // 输出结果: serialized = {"Rgb":{"r":30,"g":30,"b":30}}
    println!("serialized = {}", serialized);
}

#[serde(deserialize_with = "path")]

使用 path 函数 进行反序列化,该序列化函数声明为:fn<'de, D>(D) -> Result<FIELDS, D::Error> where D: Deserializer<'de>

#[serde(with = "module")]

serialize_withdeserialize_with的组合。Serde将使用$module::serialize作为serialize_with的值,$module::deserialize作为deserialize_with的值。

#[serde(bound = "T: MyTrait")]

序列化和反序列化的where子句表示。这将替换Serde推断的任何特征范围。

同时也支持为序列化和反序列化分别指定:

  • #[serde(bound(serialize = "T: MySerTrait"))]
  • #[serde(bound(deserialize = "T: MyDeTrait"))]
  • #[serde(bound(serialize = "T: MySerTrait", deserialize = "T: MyDeTrait"))]

#[serde(borrow)]#[serde(borrow = "'a + 'b + ...")]

使用零拷贝反序列化从反序列化程序借用该字段的数据。仅允许在newtype变体(只有一个字段的元组变体)上使用。

#[serde(other)]

如果枚举标记不是此枚举中其他变体之一的标记,则反序列化此变体。仅允许在内部标记或邻接标记枚举内的单位变体上。

例如,如果我们有一个内部标记的枚举serde(tag = "variant"),其中包含变体AB和被标记为serde(other)Unknown,则在输入的"variant"字段既不是"A"也不是"B"时,Unkonwn变体将被反序列化。

#[serde(untagged)]

不会对内容进行任何标记字段包裹。untagged的变体必须在枚举定义中排在最后。

字段属性

#[serde(rename = "name")]

使用给定名称而不是其Rust名称序列化和反序列化此字段。这对于将字段序列化为camelCase或序列化名称为保留Rust关键字的字段很有用。

允许为序列化和反序列化单独指定名称:

  • #[serde(rename(serialize = "ser_name"))]
  • #[serde(rename(deserialize = "de_name"))]
  • #[serde(rename(serialize = "ser_name", deserialize = "de_name"))]

#[serde(alias = "name")]

从给定名称或其Rust名称反序列化此字段。可以重复为同一字段指定多个可能的名称。

#[serde(default)]

如果反序列化时该值不存在,请使用Default::default()生成默认值。

#[serde(default = "path")]

如果反序列化时该值不存在,则调用函数以获取默认值。给定的函数必须可以调用为fn()->T。例如default="empty_value"将调用empty_value(),而default="SomeTrait::some_default"将调用SomeTrait::some_default()

#[serde(flatten)]

展开该字段,也就是将该字段内部抽到当前结构。

注意:此属性不支持与使用deny_unknown_fields的结构结合使用。外部或内部扁平化结构都不应使用该属性。

#[serde(skip)]

跳过此字段:不会序列化或反序列化它。

反序列化时,Serde将使用Default::default()default="…"给出的函数来获取该字段的默认值。

#[serde(skip_serializing)]

序列化时跳过此字段,反序列化时不跳过此字段。

#[serde(skip_deserializing)]

反序列化时跳过此字段,但序列化时不跳过。

反序列化时,Serde将使用Default::default()default="…"给出的函数来获取该字段的默认值。

#[serde(skip_serializing_if = "path")]

调用一个函数来确定是否跳过序列化该字段。给定的函数必须可以作为fn(&T)->bool调用,尽管它可能是T上的泛型。例如skip_serializing_if="Option::is_none"如果值是 None,那么就会跳过。

#[serde(serialize_with = "path")]

使用不同于Serialize实现的函数序列化此字段。给定函数声明需要为fn<S>(&T, S) -> Result<S::Ok, S::Error> where S: Serializer,尽管它也可能是泛型T。与serialize_with一起使用的字段不需要实现Serialize

#[serde(deserialize_with = "path")]

使用不同于Deserialize实现的函数对该字段进行反序列化。给定函数声明需要为fn<'de, D>(D) -> Result<T, D::Error> where D: Deserializer<'de>,尽管它也可能是泛型T。与deserialize_with一起使用的字段不需要实现Deserialize

#[serde(with = "module")]

serialize_withdeserialize_with的组合。Serde将使用$module::serialize作为serialize_with的值,$module::deserialize作为deserialize_with的值。

#[serde(borrow)] and #[serde(borrow = "'a + 'b + ...")]

使用零拷贝反序列化从反序列化程序借用该字段的数据。

#[serde(bound = "T: MyTrait")]

???

序列化和反序列化的where子句表示。这将替换Serde推断的任何特征范围。

同时也支持为序列化和反序列化分别指定:

  • #[serde(bound(serialize = "T: MySerTrait"))]
  • #[serde(bound(deserialize = "T: MyDeTrait"))]
  • #[serde(bound(serialize = "T: MySerTrait", deserialize = "T: MyDeTrait"))]

#[serde(getter = "...")]

这在为具有一个或多个私有字段的远程类型派生Serialize时使用。

???