2.3. API设计原则之不意外性(unsurprising) Pt.3:实现serde下的Serialize和Deserialize trait、不建议实现Copy trait
2.3.1. 建议实现serde下的Serialize和Deserialize trait
serde是Rust中用于序列化(serialization)和反序列化(deserialization) 的核心库:
- 序列化(Serialization):把Rust结构体或枚举转换为JSON、YAML等格式的字符串或二进制数据。
- 反序列化(Deserialization):从JSON、YAML等格式的字符串或二进制数据解析回Rust结构体或枚举。
Serialize和Deserialize都是serde库下的trait。
Serialize trait
Serialize trait允许一个类型转换为可序列化的数据格式(如JSON、YAML、TOML)。
其主要方法有:
serialize_boolserialize_i32serialize_strserialize_struct
这些是 Serialize 实现会调用的 Serializer(及相关)trait 上的方法;Serialize trait 本身只要求实现 serialize。
其定义是:
#![allow(unused)]
fn main() {
pub trait Serialize {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer;
}
}
我们用一个例子来介绍如何手动实现Serialize trait:
#![allow(unused)]
fn main() {
use serde::ser::{Serialize, SerializeStruct, Serializer};
struct Point {
x: i32,
y: i32,
}
impl Serialize for Point {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut state = serializer.serialize_struct("Point", 2)?;
state.serialize_field("x", &self.x)?;
state.serialize_field("y", &self.y)?;
state.end()
}
}
}
serializer.serialize_struct("Point", 2)?创建一个结构体序列化对象,2 代表字段数量state.serialize_field("x", &self.x)?依次序列化结构体字段state.end()结束序列化
Deserialize trait
Deserialize trait允许从各种数据格式解析Rust类型。
其主要方法有:
deserialize_booldeserialize_i32deserialize_stringdeserialize_struct
这些是 Deserialize 实现通过 Visitor 驱动的 Deserializer(及相关)trait 上的方法;Deserialize trait 本身只要求实现 deserialize。
其定义是:
#![allow(unused)]
fn main() {
pub trait Deserialize<'de>: Sized {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>;
}
}
deserialize方法的作用是:使用deserializer从数据格式解析Rust类型
我们用一个例子来介绍如何手动实现Deserialize trait:
#![allow(unused)]
fn main() {
use serde::de::{self, Deserialize, Deserializer, Visitor, MapAccess};
use std::fmt;
struct Point {
x: i32,
y: i32,
}
impl<'de> Deserialize<'de> for Point {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct PointVisitor;
impl<'de> Visitor<'de> for PointVisitor {
type Value = Point;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a struct Point with fields x and y")
}
fn visit_map<M>(self, mut map: M) -> Result<Point, M::Error>
where
M: MapAccess<'de>,
{
let mut x = None;
let mut y = None;
while let Some(key) = map.next_key::<String>()? {
match key.as_str() {
"x" => x = Some(map.next_value()?),
"y" => y = Some(map.next_value()?),
_ => {}
}
}
let x = x.ok_or_else(|| de::Error::missing_field("x"))?;
let y = y.ok_or_else(|| de::Error::missing_field("y"))?;
Ok(Point { x, y })
}
}
deserializer.deserialize_struct("Point", &["x", "y"], PointVisitor)
}
}
}
PointVisitor结构体用于解析JSON字段visit_map解析x和y的值,确保字段存在
使用#[derive(Serialize, Deserialize)]标注自动实现Serialize和Deserialize
手动实现Serialize和Deserialize非常繁琐,通常我们会使用serde_derive宏:
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize, Debug)]
struct Point {
x: i32,
y: i32,
}
fn main() {
let p = Point { x: 10, y: 20 };
let serialized = serde_json::to_string(&p).unwrap();
println!("Serialized: {}", serialized); // {"x":10,"y":20}
let deserialized: Point = serde_json::from_str(&serialized).unwrap();
println!("Deserialized: {:?}", deserialized); // Point { x: 10, y: 20 }
}
使用了Serialize和Deserialize的例子
use serde::{Serialize, Deserialize};
use serde_json;
#[derive(Serialize, Deserialize, Debug)]
struct User {
name: String,
age: u32,
}
fn main() {
let user = User {
name: "Alice".to_string(),
age: 30,
};
// 序列化
let json_str = serde_json::to_string(&user).unwrap();
println!("Serialized JSON: {}", json_str);
// 反序列化
let deserialized: User = serde_json::from_str(&json_str).unwrap();
println!("Deserialized: {:?}", deserialized);
}
输出:
Serialized JSON: {"name":"Alice","age":30}
Deserialized: User { name: "Alice", age: 30 }
其他注意事项
serde下的serde_derive crate提供了机制,可以覆盖单个字段或枚举变体的序列化。由于serde是第三方库,你可能不希望强制添加对它的依赖。
大多数库都选择了提供了serde功能(feature),只有当用户选择启用该功能时才添加对serde的支持。
也就是说,你要在你的crate里这么写:
[dependencies]
serde = { version = "1.0", optional = true }
[features]
serde = ["dep:serde"]
- 在
[dependencies]这一块引入了serde,除了写了语义版本之外,还有optional = true,这代表着是一个可选的依赖。这意味着默认情况下不包含 serde,除非显式启用它。 [features]这一块写了serde = ["dep:serde"],意思是当用户启用serde feature时,才会启用 serde 依赖"dep:serde"这部分表示依赖 serde 这个库(dep:是依赖的前缀,告诉Cargo这个feature依赖serde)
别人要用你的crate(假设my_crate是你的crate的名字)时这么写就可以启用serde:
[dependencies]
my_crate = { version = "0.1", features = ["serde"] }
2.3.2. 不建议实现Copy trait
用户通常不期望类型实现Copy trait。如果用户想要副本的话,通常会调用clone方法。
Copy trait改变了移动给定类型值的语义(Copy trait的语义与实现要求详见 1.9.2. 如何实现Copy trait)。看个例子:
#[derive(Debug,Copy, Clone)]
struct Point {
x: i32,
y: i32,
}
fn main() {
let point1 = Point { x: 10, y: 10 };
let point2 = point1;
println!("{:?}", point1);
println!("{:?}", point2);
}
point1的值赋给了point2。一般来说point1至此之后就会失效,但是由于Point结构体实现了Copy trait,所以point1的值赋给了point2发生的是复制而不是移动,point1至此之后仍然保持有效。这点会让用户感到惊讶,所以不建议实现Copy trait。
除此以外,实现Copy的类型会有很多限制,一个最初简单的类型很容易变得不再满足Copy trait的要求。例如持有String或其他不支持Copy trait的类型都不得不移除Copy trait。