文章目录
- [1 serde 框架](#1 serde 框架)
- [2 使用第三方库序列化(serde_yaml)](#2 使用第三方库序列化(serde_yaml))
-
- [2.1 序列化](#2.1 序列化)
-
- [1 方法](#1 方法)
- [2.2 反序列化](#2.2 反序列化)
-
- [1 简单示例](#1 简单示例)
- [2 方法](#2 方法)
- [3 自定义序列化反序列化](#3 自定义序列化反序列化)
-
- [3.1 自定义序列化](#3.1 自定义序列化)
- [3.2 自定义反序列化](#3.2 自定义反序列化)
- 程序完整代码
- 参考链接
1 serde 框架
作用:可以将结构体、枚举、向量、哈希表等rust数据转换为各种各式的数据(目前为16种)例如JSON
、YALM
、TOML
等,以及将这些格式的数据转换为原始的rust数据类型
简介
Serde
是主流的rust序列化、反序列化框架。设计上,基于rust的静态类型系统和元编程(宏)的能力,使Serde
序列化的执行速度与手写序列化器的速度相同。
使用上及其简单
- 用户为自己的类型实现
Serialize
和Deserialize
特质即可(大多数使用derive
宏实现) - 序列化提供商,提供
Serializer
和Deserializer
特征的实现即可。
Serde数据模型
Serde
数据模型是与rust数据结构和数据格式进行交互的API。可以将其视为Serde
的类型系统,Serde
将rust类型分为29种。
- 针对需要序列化的类型,用户需要实现
serialize
:根据rust类型调用参数Serializer
上的方法,而Serializer
的实现有序列化提供商提供 - 针对需要反序列化的类型,用户需要实现
Deserialize
:根据rust类型调用参数Serializer
上的方法,传递一个实现了Visitor
的类型
29种类型
- 14 基础类型
- bool
- i8, i16, i32, i64, i128
- u8, u16, u32, u64, u128
- f32, f64
- char
- string
- 有长度标记的UTF-8 字节数据(不是
\0
结尾的形式),可能长度为0 - 在序列化时,所有类型的字符串被同等处理。在反序列化时,有三种方案:transient, 拥有所有权, 和借用。参见《理解反序列化生命周期》,(Serde使用零拷贝技术)
- 有长度标记的UTF-8 字节数据(不是
- byte array -
[u8]
(字节数组)- 与字符串相似,在反序列化期间,字节数组可以是 transient, 拥有所有权, 和借用
- option
- None 或者 Value
- unit (元组)
- Rust 中
()
的类型,它表示不包含数据的匿名值
- Rust 中
- unit_struct
- 例如
struct Unit
或PhantomData<T>
,它表示不包含数据的命名值
- 例如
- unit_variant
- 例如 在
enum E { A, B }
中的E::A
和E::B
- 例如 在
- newtype_struct
- 例如
struct Millimeters(u8)
- 例如
- newtype_variant
- 例如 在
enum E { N(u8) }
中的E::N
- 例如 在
- seq
- 可变大小的异质序列
- 例如
Vec<T>
或者HashSet<T>
- 序列化时,长度在遍历之前可能是未知的。在反序列化时,通过 查看数据 可以得知长度
- 注意,像
vec![Value::Bool(true), Value::Char('c')]
之类的同质Rust集合可以序列化为异构Serde seq,在这种情况下,包含Serde bool和Serde char。
- tuple
- 大小静态可知的异质序列
- 例如
(u8,)
或(String, u64, Vec<T>)
或[u64; 10]
- 其长度在反序列化时就已知道,无需查看数据
- tuple_struct
- 命名元组,例如
struct Rgb(u8, u8, u8)
- 命名元组,例如
- tuple_variant
- 例如 在
enum E { T(u8, u8) }
中 的E::T
- 例如 在
- map
- 大小可变的异类键值对,例如
BTreeMap <K, V>
。进行序列化时,在遍历所有条目之前,长度可能未知,也可能未知。反序列化时,通过 查看数据 可以得知长度
- 大小可变的异类键值对,例如
- struct
- 静态大小的异构键值对,其中的键是编译时常量字符串,并且在反序列化时无需查看序列化数据即可知道
- 例如
struct S { r: u8, g: u8, b: u8 }
- struct_variant
- 例如 在
enum E { S { r: u8, g: u8, b: u8 } }
中 的E::S
- 例如 在
属性
属性用于使用派生宏的一些配置,主要分为三类:
- 容器属性
Container attributes
:应用在枚举
和结构体上
- 变体属性
Variant attributes
:应用在枚举
的变体
上 - 字段属性
Field attributes
:应用在结构体
和枚举变体
的 字段上
1)容器属性
-
#[serde(rename_all = "...")]
- 根据给定的大小写约定重命名所有字段(结构)或 variants(枚举)。
"..."
的可选值为"lowercase"
,"UPPERCASE"
,"PascalCase"
,"camelCase"
,"snake_case"
,"SCREAMING_SNAKE_CASE"
,"kebab-case"
,"SCREAMING-KEBAB-CASE"
- kebab-case:短横线命名法
- 根据给定的大小写约定重命名所有字段(结构)或 variants(枚举)。
-
#[serde(deny_unknown_fields)]
- 指定遇到未知字段时,在反序列化期间始终出错。
- 默认情况下,对于诸如JSON之类的自描述格式,未知字段将被忽略
2)变体属性
#[serde(alias = "name")]
- 反序列化时,对应的别名
- 允许配置多个
#[serde(skip)]
- 跳过序列化或反序列化此 variant
- 尝试序列化时将报错
- 尝试反序列化时将报错
3)字段属性
#[serde(alias = "name")]
- 反序列化时,对应的别名
- 允许配置多个
#[serde(skip)]
- 跳过此字段:不序列化或反序列化
- 反序列化时,Serde将使用
Default::default()
或default = "..."
生成该值
2 使用第三方库序列化(serde_yaml)
2.1 序列化
1 方法
-
to_string
-
原型
rustpub fn to_string<T>(value: &T) -> Result<String, Error> where T: ?Sized + Serialize,
-
功能:将给定的数据结构序列化为 YAML 字符串。
-
示例
rustfn to_string() -> Result<(), Box<dyn std::error::Error>>{ let people = People{ name:"Alice".to_string(), age:30, email:"123456".to_string(), }; let yaml_string = serde_yaml::to_string(&people)?; println!("{}", yaml_string); Ok(()) }
-
-
to_value
-
原型
rustpub fn to_value<T>(value: T) -> Result<Value, Error> where T: Serialize,
-
功能:将 转换
T
为serde_yaml::Value
可以表示任何有效 YAML 数据的枚举。如果想要一个
Value
而不是字符串,你可以使用serde_yaml::ser::Serializer
来手动序列化你的结构体到Value
。但这样做通常比直接序列化到字符串更加复杂和低效。 -
示例
rsut
-
-
to_writer
-
原型
rustpub fn to_writer<W, T>(writer: W, value: &T) -> Result<(), Error> where W: Write, T: ?Sized + Serialize,
-
功能:将给定的数据结构作为 YAML 序列化到 IO 流中。
-
示例
rustfn to_writer() { let people = People{ name:"Alice".to_string(), age:2, email:"123456".to_string(), }; let mut out = Vec::new(); serde_yaml::to_writer(&mut out, &people).unwrap(); let yaml_write = out.clone(); fs::write("/home/wangm/rust_exercise/serde_learn/config.yaml", yaml_write).unwrap(); let yaml_str = String::from_utf8(out).unwrap(); println!("{}", yaml_str); }
-
2.2 反序列化
1 简单示例
rust
#[derive(Debug,Deserialize)]
pub struct People {
name: String,
age: u8,
email:String,
}
fn main() {
// 反序列化
let json2 = r#"
{
name: wangmeng,
age: 2,
email: 123456789
}
"#;
let r2: People = serde_yaml::from_str(json2).unwrap();
println!("People = {:#?}", r2);
println!("people name: {}", r2.name);
println!("people age: {}", r2.age);
println!("people email: {}", r2.email);
}
执行结果:
bash
People = People {
name: "wangmeng",
age: 2,
email: "123456789",
}
people name: wangmeng
people age: 2
people email: 123456789
2 方法
-
from_reader
-
函数原型
rustpub fn from_reader<R, T>(rdr: R) -> Result<T, Error> where R: Read, T: DeserializeOwned,
-
功能:从yaml的io流中反序列化类型示例
-
示例
rustuse std::fs::File; use std::io::Read; use std::fmt; use serde::Deserialize; use serde::ser::{Serialize, SerializeStruct, Serializer}; use serde::de::{self, Deserializer, Visitor}; fn print(people:People) { println!("{:#?}", people); println!("people name: {}", people.name); println!("people age: {}", people.age); println!("people email: {}", people.email); } fn from_reader() -> Result<(), Box<dyn std::error::Error>> { println!("this is a from_reader test"); let file = File::open("/home/wangm/rust_exercise/serde_learn/config.yaml")?; let people:People = serde_yaml::from_reader(file)?; print(people); Ok(()) } fn main() { // 反序列化 let _a = from_reader(); // let file = File::open("/home/wangm/rust_exercise/serde_learn/config.yaml")?; // let people:People = serde_yaml::from_reader(file)?; // println!("{:#?}", people); // Ok(()) }
config.yaml
yamlname: Alice age: 30 email: alice@example.com
在改程序中,直接打开文件即可,将文件句柄传递给反序列化函数
-
-
from_slice
-
原型
rustpub fn from_slice<'de, T>(v: &'de [u8]) -> Result<T, Error> where T: Deserialize<'de>,
-
功能:从字节反序列化
-
示例
rustfn from_slice() { let file = "/home/wangm/rust_exercise/serde_learn/config.yaml"; match fs::read(file) { Ok(f) => { let yaml_data = f.as_slice(); let people: People = match serde_yaml::from_slice(yaml_data) { Ok(u) => u, Err(e) => { println!("Error parsing YAML: {}", e); return; } }; print(people); } Err(_e) => { println!("file open false"); } } }
-
-
from_value
-
原型
rustpub fn from_value<T>(value: Value) -> Result<T, Error> where T: DeserializeOwned,
-
功能:在不知道要反序列化内容的具体类型时使用,如果你不确定 YAML 文档的确切结构,或者它可能包含多种不同的数据结构,你可以先将其解析为
serde_yaml::Value
,然后根据需要动态地决定如何进一步处理它。
-
-
from_str
-
原型
rustpub fn from_str<'de, T>(s: &'de str) -> Result<T, Error> where T: Deserialize<'de>,
-
功能:从 YAML 文本字符串反序列化类型实例
-
示例
./poem.txt
内容yaml# == Classic == # This is a shorthand to override some of the options to be backwards compatible # with `ls`. It affects the "color"->"when", "sorting"->"dir-grouping", "date" # and "icons"->"when" options. # Possible values: false, true classic: 12 # == Blocks == # This specifies the columns and their order when using the long and the tree # layout. # Possible values: permission, user, group, context, size, date, name, inode, git blocks: test1233
cargo.toml
rust[package] name = "all_test" version = "0.1.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] serde_yaml = "0.9" //这个库是用来解析yaml文件的 serde = { version = "1.0", features = ["derive"] } // 这是一个序列化和反序列化的框架
main.rs
rustuse std::{fs, string}; use std::path::{Path, PathBuf}; use serde::{Serialize, Deserialize}; //定义结构体,yaml解析的内容是结构体 #[derive(Serialize, Deserialize, PartialEq, Debug)] // 添加序列化和反序列化的属性 pub struct Config { pub classic: i32, pub blocks: String, } fn main() -> Result<(), serde_yaml::Error> //不带返回值的还没有测试过 { let file = "./poem.txt"; match fs::read(file) { //读取文件 Ok(f) => { let info = String::from_utf8_lossy(&f); //获取文件内容,去除无效字符 let yaml:Config = serde_yaml::from_str(&info)?; //解析yaml println!("{:?}",yaml); Ok(()) }, Err(_e) => { println!("file read false"); Ok(()) }, } }
执行结果:
bashConfig { classic: 12, blocks: "test1233" }
-
3 自定义序列化反序列化
若要数据类型支持序列化和反序列化,则该类型需要实现Serialize
和Deserialize
trait。
Serde提供了rust基础类型和标准库类型的Serialize
和Deserialize
实现。对于自定义类型,可以自行实现Serialize
和Deserialize
trait。另外,serde提供一个宏serde_derive
来自动为结构体类型和枚举类型生成Serialize
和Deserialize
。该特性需要rust编译器版本在1.31
及以上,并且在cargo.toml
文件配置serde依赖时,需要features
指定该特性。例如:
toml
[dependencies]
serde = { version = "1.0", features = ["derive"] }
在代码中引用并使用:
rust
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize, Debug)]
struct Point {
x: i32,
y: i32,
}
Serializer
和Deserializer
由第三方crate提供,例如serde_json,serde_yaml等。
3.1 自定义序列化
1)代码
rust
use serde::ser::{Serialize,SerializeStruct,}; // 序列化
// #[derive(Serialize)] // 用这种方式
// 普通结构体 步骤如下
// 1. serilaize_struct
// 2. serialize_field
// 3. end
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,
{
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(); // 结束序列化
}
}
3.2 自定义反序列化
结构体的反序列化比枚举的反序列化更复杂。枚举反序列化是直接根据类型反序列化即可,结构体的反序列化需要将反序列化的内容先变为枚举类型,在继续反序列化。
自定义反序列化器的情况:
- 非标准格式:当需要处理的数据不是标准的json、yaml、toml等时
- 复杂的数据结构:它不能直接映射到标准格式中的表示方法
- 性能优化:
- 自定义验证和错误处理:标准的序列化/反序列化库可能只提供基本的验证和错误处理机制。有时,可能需要更复杂的验证逻辑或更详细的错误报告。
- 向前/向后兼容:应用程序需要与旧版本的数据进行交互,或者需要支持不同版本的数据格
1)框架
实现Deserialize trait 来告诉serde xxx类型支持反序列化
rust
impl Deserialize for struct_xxx {
fn deserialize<D>(deserializer:D) -> Result<Self, D::Error>
where
D:Deserializer<'de>,
{
// 各种deserializer_xxx 函数进行反序列化
deserializer.deserializer_xxx();
}
}
遍历访问者
rust
// 自定义反序列化器
struct xxxVisitor;
impl<'de> Visitor<'de> for xxxVisitor {
type Value = xxx;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
}
fn visit_xxx();
}
2)代码
rust
use serde::{Deserialize, Deserializer,};
#[derive(Debug)]
enum Age {
Numeric(u64),
// Numeric,
Child,
}
#[derive(Deserialize, Debug)]
struct Person {
name: String,
age: Age,
hobbies: Vec<String>,
}
// 由于枚举可能包含不同的JSON表示形式,您可能需要提供一个自定义的反序列化函数
// 例如,如果您希望"age"字段可以是一个数字或一个字符串(如"child")
impl<'de> Deserialize<'de> for Age {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
struct AgeVisitor;
impl<'de> serde::de::Visitor<'de> for AgeVisitor {
type Value = Age;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("a number or 'child' string")
}
fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E> // 默认类型是64 改成u32后解析报错
where
E: serde::de::Error,
{
Ok(Age::Numeric(value))
}
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
if value == "child" {
Ok(Age::Child)
} else {
Err(serde::de::Error::custom(format!("invalid age: {}", value)))
}
}
// 如果需要支持其他类型,可以添加更多的visit方法
}
deserializer.deserialize_any(AgeVisitor)
}
}
pub fn custom_deserialize() {
let json = r#"
{
"name": "Alice",
"age": "child",
"hobbies": ["reading", "swimming"]
}
"#;
let json2 = r#"
{
"name": "Alice",
"age": 8,
"hobbies": ["reading", "swimming"]
}
"#;
let person: Person = serde_yaml::from_str(json).unwrap();
println!("{:#?}", person);
let person: Person = serde_yaml::from_str(json2).unwrap();
println!("{:#?}", person);
}