serde 介绍
serde 是用于通用数据的序列化和反序列 化的框架, 这里查看在线文档, 具体实现 还需要其他的包, 比如将 rust 结构体转换为 json 字符串, 或者将 json 转换 为 rust 结构体 就需要 serde_json
同理, yaml/toml/json5 等其他数据格式需要其对应的包
json
添加依赖
toml
[dependencies]
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"序列化
- Rust 结构体必须实现
serde::Serialize这个 trait - 实现接口后就会提供这个方法:
to_string
所谓的序列化 就是将 rust 中的结构体/枚举转换为指定格式的字符串 (如 json 格式)
rust
use serde::{Deserialize, Serialize};
use serde_json;
// 关键: 必须要实现则两个 trait 才能序列化
// 注意: 如果字段的值是 struct, 那它也必须实现这两个 trait
#[derive(Debug, Serialize, Deserialize)]
struct User {
username: String,
password: Option<String>, // 可选字段
userinfo: UserInfo,
}
#[derive(Debug, Serialize, Deserialize)]
struct UserInfo {
age: u8,
height: u8,
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut user = User {
username: String::from("alice"),
password: Some(String::from("123456")),
userinfo: UserInfo {
age: 19,
height: 190,
},
};
// 1.将 Rust Struct 转换为字符串, 返回一个 Result
let str = serde_json::to_string(&user)?;
println!("{str}");
// {"username":"alice","password":"123456","userinfo":{"age":19,"height":190}}
// 2.可选字段,会被转为 null(JS 中的空值)
user.password = None;
let str2 = serde_json::to_string(&user)?;
println!("{str2}");
// {"username":"alice","password":null,"userinfo":{"age":19,"height":190}}
// 3.转为带有缩进与换行的json格式, 这个方法是 json create 独有的
// 不是来自于 serde::{Deserialize, Serialize}; 接口中的标准方法
// 其他实现只有 to_string 和 from_str 两个方法
let str3 = serde_json::to_string_pretty(&user)?;
println!("{str3}");
// {
// "username": "alice",
// "password": null,
// "userinfo": {
// "age": 19,
// "height": 190
// }
// }
Ok(())
}反序列化
- Rust 结构体必须实现
serde::DeSerialize这个 trait - 实现接口后就会提供这个方法:
from_str这个 trait
所谓的 反序列化就是将字符串解析为rust中的结构体/枚举 以方便程序处理
rust
use serde::{Deserialize, Serialize};
use serde_json;
// 关键: 必须要实现则两个 trait 才能序列化
// 注意: 如果字段的值是 struct, 那它也必须实现这两个 trait
#[derive(Debug, Serialize, Deserialize)]
struct User {
username: String,
password: Option<String>, // 可选字段
userinfo: UserInfo,
}
#[derive(Debug, Serialize, Deserialize)]
struct UserInfo {
age: u8,
height: u8,
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let str = r##"{
"username": "alice",
"password": "123456",
"userinfo": {
"age": 18,
"height": 180
}
}"##;
// 原字符串
println!("original json string:");
println!("{str}");
// 1.将 json 字符串解析为Rust Struct
let user = serde_json::from_str::<User>(str)?;
println!("{user:?}");
// User {
// username: "alice",
// password: Some("123456"),
// userinfo: UserInfo {
// age: 18,
// height: 180
// }
// }
// 2.可选字段, 会解析为 None
let str = r##"{
"username": "alice",
"userinfo": {
"age": 18,
"height": 180
}
}"##;
println!("original json string:");
println!("{str}");
let user = serde_json::from_str::<User>(str)?;
println!("{user:?}");
Ok(())
}序列化:字段重命名
由于 Rust 推荐代码风格 struct 所有字段都是 snake_case, 但是序列化时候, 可能不是这样, 所以需要重命名
#[serde(rename_all = "camelCase")]作用于整个结构体/枚举
| 取值 | 结果示例值 |
|---|---|
| "camelCase" | userName |
| "PascalCase" | UserName |
| "snake_case" | user_name |
| "SCREAMING_SNAKE_CASE" | USER_NAME |
| "kebab-case" | user-name |
| "SCREAMING-KEBAB-CASE" | USER-NAME |
| "lowercase" | username |
| "UPPERCASE" | USERNAME |
rust
use serde::{Deserialize, Serialize};
use serde_json;
#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "PascalCase")]
struct User {
user_name: String,
user_age: u8,
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let user = User {
user_name: String::from("alice"),
user_age: 11,
};
let str3 = serde_json::to_string_pretty(&user)?;
println!("{str3}");
// {
// "UserName": "alice",
// "UserAge": 11
// }
Ok(())
}rust
use serde::{Deserialize, Serialize};
use serde_json;
#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "PascalCase")]
struct User {
user_name: String,
// 作用于结构体/枚举具体的字段
// rename 的优先级 rename_all 更高
#[serde(rename = "kebab-case")]
user_age: u8,
// rename 可以手动指定字段名, 而不使用内置的那些值
#[serde(rename = "user_height")]
height: u8,
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let user = User {
user_name: String::from("alice"),
user_age: 11,
height: 32,
};
let str3 = serde_json::to_string_pretty(&user)?;
println!("{str3}");
// {
// "UserName": "alice",
// "kebab-case": 11,
// "user_height": 32
// }
Ok(())
}反序列化:字段默认值
rust
use serde::{Deserialize, Serialize};
use serde_json;
// 因为: rust 是强类型语言, 序列化之前, 它肯定有值, 否则无法编译
// 所以: 只需要测试反序列化时候的值就行
// 自定义序列化时, 字段的值
#[derive(Debug, Default, Serialize, Deserialize)]
// 1. 这样使用会调用 User::defalt(), 所以必须实现 Default trait
#[serde(default)]
struct User {
// 2. struct 字段的值如果是 struct(String是一个struct),那么
// 它也必须实现 Default 这个 trait
user_name: String,
user_age: u8, // 会调用 u8::default()
user_height: u8,
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let str = r##"{}"##; // 空json对象字符串
let user = serde_json::from_str::<User>(str)?;
println!("{user:?}");
// 输出:
// User {
// user_name: "",
// user_age: 0,
// user_height: 0
// }
Ok(())
}rust
use serde::{Deserialize, Serialize};
use serde_json;
// 使用自定义的函数来设置默认值
fn default_user_age() -> u8 {
1
}
#[derive(Debug, Default, Serialize, Deserialize)]
#[serde(default)]
struct User {
user_name: String,
#[serde(default = "default_user_age")]
user_age: u8, // 会调用 default_user_age 而不是 u8::default()
user_height: u8,
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let str = r##"{}"##; // 空json对象字符串
let user = serde_json::from_str::<User>(str)?;
println!("{user:?}");
// 输出:
// User {
// user_name: "",
// user_age: 1,
// user_height: 0
// }
Ok(())
}反序列化: 字段别名
rust
use serde::{Deserialize, Serialize};
use serde_json;
#[derive(Debug, Default, Serialize, Deserialize)]
struct User {
// 别名
#[serde(alias = "username")]
user_name: String,
// 可以设置多个 别名
#[serde(alias = "age", alias = "userAge", alias = "UserAge")]
user_age: u8,
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let str = r##"{
"username": "alice",
"age": 11
}"##;
let user = serde_json::from_str::<User>(str)?;
println!("{user:?}");
// 输出:
// User {
// user_name: "alice",
// user_age: 11
// }
let str = r##"{
"username": "tom",
"userAge": 12
}"##;
let user = serde_json::from_str::<User>(str)?;
println!("{user:?}");
// User {
// user_name: "tom",
// user_age: 12
// }
Ok(())
}统一设置枚举结构
rust
use serde::{Deserialize, Serialize};
use serde_json;
#[derive(Debug, Default, Serialize, Deserialize)]
enum UserInfo {
Man(u8), // 男:age
Woman(u8), // 女:age
// 将这个变体标记为默认值,需要配置 #[derive(Default)] 使用
#[default]
Unknown, // 保密
}
#[derive(Debug, Default, Serialize, Deserialize)]
struct User {
user_name: String,
user_info: UserInfo,
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let user = User {
user_name: String::from("tom"),
user_info: UserInfo::Man(12),
};
let str = serde_json::to_string_pretty(&user)?;
println!("{str}");
// {
// "user_name": "tom",
// "user_info": {
// "Man": 12
// }
// }
let user = User {
user_name: String::from("tom"),
user_info: UserInfo::Unknown,
};
let str = serde_json::to_string_pretty(&user)?;
println!("{str}");
// {
// "user_name": "tom",
// "user_info": "Unknown"
// }
// 在没有设置 tag 和 content 时: 序列化后的结构都不一样
Ok(())
}rust
use serde::{Deserialize, Serialize};
use serde_json;
#[derive(Debug, Default, Serialize, Deserialize)]
#[serde(tag = "gender", content = "age", rename_all = "UPPERCASE")]
enum UserInfo {
Man(u8), // 男:age
Woman(u8), // 女:age
// 将这个变体标记为默认值,需要配置 #[derive(Default)] 使用
#[default]
Unknown, // 保密
}
#[derive(Debug, Default, Serialize, Deserialize)]
struct User {
user_name: String,
user_info: UserInfo,
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let user = User {
user_name: String::from("tom"),
user_info: UserInfo::Man(12),
};
let str = serde_json::to_string_pretty(&user)?;
println!("{str}");
// {
// "user_name": "tom",
// "user_info": {
// "gender": "MAN",
// "age": 12
// }
// }
let user = User {
user_name: String::from("tom"),
user_info: UserInfo::Unknown,
};
let str = serde_json::to_string_pretty(&user)?;
println!("{str}");
// {
// "user_name": "tom",
// "user_info": {
// "gender": "UNKNOWN"
// }
// }
//
// 统一序列化后的结构: user_info 必须是一个 object
Ok(())
}flatten 摊平结构字段
所谓的摊平结构的意思是:
txt
{
"keyword": "Rust",
"pagination": {
"page": 1,
"limit": 10
}
}
摊平 pagination 字段:
{
"keyword": "Rust",
"page": 1,
"limit": 10
}rust
use serde::{Deserialize, Serialize};
use serde_json;
#[derive(Serialize, Deserialize, Debug)]
struct Pagination {
page: u32,
limit: u8,
}
#[derive(Serialize, Deserialize, Debug)]
struct SearchQuery {
keyword: String,
#[serde(flatten)]
pagination: Pagination,
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let sq = SearchQuery {
keyword: String::from("Rust"),
pagination: Pagination { page: 1, limit: 10 },
};
let str = serde_json::to_string_pretty(&sq)?;
println!("{str}");
// {
// "keyword": "Rust",
// "page": 1,
// "limit": 10
// }
let str2 = r#"
{
"keyword": "Rust",
"page": 1,
"limit": 10
}"#;
let sq2 = serde_json::from_str::<SearchQuery>(&str2)?;
println!("{sq2:?}");
// SearchQuery {
// keyword: "Rust",
// pagination: Pagination {
// page: 1,
// limit: 10
// }
// }
// 注意: 摊平是双向的, 序列化和反序列化都同时生效
let str3 = r#"
{
"keyword": "Rust",
"pagination": {
"page": 1,
"limit": 10
}
}"#;
// Error: Error("missing field `page`", line: 8, column: 5)
let sq3 = serde_json::from_str::<SearchQuery>(&str3)?;
println!("{sq3:?}");
Ok(())
}反序列化: 收集剩余字段
rust
use std::collections::HashMap;
use serde::{Deserialize, Serialize};
use serde_json;
#[derive(Serialize, Deserialize, Debug)]
struct SearchQuery {
keyword: String,
page: u32,
limit: u8,
#[serde(flatten)]
extra: HashMap<String, serde_json::Value>, // 收集所有未知字段
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let str = r#"{
"keyword": "Rust",
"page": 1,
"limit": 10,
"count": 111,
"sort_by": "id",
"order_by": "desc"
}"#;
let sq = serde_json::from_str::<SearchQuery>(&str)?;
println!("{sq:?}");
// SearchQuery {
// keyword: "Rust",
// page: 1,
// limit: 10,
// extra: {
// "count": Number(111),
// "sort_by": String("id"),
// "order_by": String("desc")
// }
// }
// 注: 此时 count 并不是一个标量类型, 而是一个结构体 serde::Number(111)
let count_value = sq.extra.get("count").unwrap();
// 将结构体转为 Rust 标量类型(通用转换方法)
let count = serde_json::from_value::<i32>(count_value.clone())?;
println!("{count:?}"); // i32
// 使用内置快捷转换方法 as_str/as_u64/as_i64/as_array 这些方法是由
// serde_json 提供的: https://docs.rs/serde_json/1.0.151/serde_json/enum.Value.html
let count = count_value.as_u64().unwrap();
println!("{count:?}"); // u64
// 同理, serde::String() 也是需要转换的
Ok(())
}json5
注意 json 和 json5 格式的区别, 虽然都是字符串描述数据结构但是 json5 更加强大
rust
use serde::{Deserialize, Serialize};
use std::net::Ipv4Addr;
use json5;
#[derive(Debug, Deserialize, Serialize)]
struct ServerConfig {
workers: u64,
domain: String,
ip: Ipv4Addr,
port: u16,
}
fn main() {
// json5 string -> rust struct instance
let server_config_json = r#"{
// 服务器线程数量
workers: 5,
// 服务器域名
domain: "www.example.com",
// 服务器ip
ip: "127.0.0.1",
// 服务器监听的端口
port: 6789
}"#;
let config: ServerConfig = json5::from_str(server_config_json).unwrap();
println!("config");
println!("{:?}", config);
// rust struct instance -> json5 string
let server_config = ServerConfig {
workers: 10,
domain: "localhost".to_string(),
ip: Ipv4Addr::new(127, 0, 0, 1),
port: 9876,
};
let config_str = json5::to_string(&server_config).unwrap();
println!("config_str:\n{}", config_str);
}toml
[dependencies]
json5 = "1.3"
serde = { version = "1.0", features = ["derive"] }yaml
rust
use std::collections::HashMap;
use serde::{Deserialize, Serialize};
use serde_yaml;
#[derive(Debug, Deserialize, Serialize)]
struct Container {
image: String,
restart: Option<String>,
ports: Vec<String>,
volumes: Vec<String>,
}
#[derive(Debug, Deserialize, Serialize)]
struct DockerComposeConfig {
services: HashMap<String, Container>,
networks: Option<Vec<String>>,
volumes: Option<Vec<String>>,
}
fn main() {
// yaml string -> rust struct instance
let docker_compose_yaml = r#"
services:
app:
image: 'jc21/nginx-proxy-manager:latest'
restart: unless-stopped
ports:
- '80:80' # nginx http端口
- '443:443' # nginx https端口
- '81:81' # nginx-proxy-manager 项目端口
volumes:
- ./data:/data
- ./letsencrypt:/etc/letsencrypt
"#;
let config: DockerComposeConfig = serde_yaml::from_str(docker_compose_yaml).unwrap();
println!("config \n {:?} \n", config);
let yaml_str = serde_yaml::to_string(&config).unwrap();
println!("yaml_str \n {:?} \n", yaml_str);
}toml
[dependencies]
serde = { version = "1.0", features = ["derive"] }
serde_yaml = "0.9"toml
rust
use serde::{Deserialize, Serialize};
use std::net::Ipv4Addr;
use toml as serde_toml; // alias, keep same style with serde_json/serde_yaml
#[derive(Debug, Serialize, Deserialize)]
struct ServerAuth {
require_password: bool,
password: String,
connection_timeout: u32,
}
#[derive(Debug, Serialize, Deserialize)]
struct ServerConfig {
workers: u64,
ip: Ipv4Addr,
port: u16,
domain: Option<String>,
auth: Option<ServerAuth>,
}
fn main() {
let toml_str = r#"
# server config
workers = 10
ip = "192.168.2.1"
port = 6789
domain = "www.example.com"
# auth config
[auth]
require_password = true
password = "123456"
connection_timeout = 30
"#;
let config: ServerConfig = serde_toml::from_str(toml_str).unwrap();
println!("config:\n {:?} \n", config);
let toml_str = serde_toml::to_string(&config).unwrap();
println!("toml_str:\n{:?}\n", toml_str);
}toml
[dependencies]
serde = { version = "1.0", features = ["derive"] }
toml = "1.1"