创建项目安装依赖
sh
cargo new serde_demo
cd serde_demo
cargo add serde
serde 介绍
serde 是用于通用数据的序列化和反序列化的框架, 具体实现还需要其他的包, 比如将 rust 结构体转换为 json 字符串, 或者将 json 转换为 rust 结构体 就 需要 serde_json
同理, yaml/toml/json5 等其他数据格式需要其对应的包
json
这里使用 json, 其他格式也是一样
rust
use serde::{Deserialize, Serialize};
use std::fs;
#[derive(Serialize, Deserialize, Debug)]
struct PkgInfo {
cargo_url: String,
repo_url: Option<String>,
homepage: Option<String>,
}
// 1. 让 Package struct 实现 Serialize, Deserialize 特性
// Debug 是方便输出到控制台, 看是否转换成功
// PkgInfo 也必须要实现 Serialize, Deserialize 特性
#[derive(Serialize, Deserialize, Debug)]
struct Package {
name: String,
version: String,
author: String,
downloads: u64,
pkg_info: PkgInfo,
keywords: Vec<String>,
}
fn main() {
// 2.json string => rust struct
let mut json_file_path = String::new();
json_file_path.push_str(env!("CARGO_MANIFEST_DIR"));
json_file_path.push_str("/example.json");
let json_str = fs::read_to_string(json_file_path).unwrap();
let package: Package = serde_json::from_str(&json_str).unwrap();
println!("{:?}", package);
// 3.rust struct => json string
let pack = Package {
name: String::from("for-test-deserialize"),
version: String::from("1.0.1"),
author: String::from("secret"),
downloads: 101,
pkg_info: {
PkgInfo {
cargo_url: "http://localhost/cargo/for-test-deserialize".to_string(),
repo_url: None,
homepage: Some("http://localhost/for-test-deserialize".to_string()),
}
},
keywords: Vec::from([
"rust".to_string(),
"json".to_string(),
"serde_json".to_string(),
]),
};
let mut json_file_path = String::new();
json_file_path.push_str(env!("CARGO_MANIFEST_DIR"));
json_file_path.push_str("/example_2.json");
// json_str -> example_2.json
let json_str = serde_json::to_string(&pack).unwrap();
fs::write(json_file_path, json_str).unwrap();
println!("== finish ==");
}
toml
[dependencies]
serde = { version = "1.0.213", features = ["derive"] }
serde_json = "1.0.132"
json5
这个例子就不使用文件了, 总是要读取文件和处理路径, 还是直接使用 r#"xxx"#
原始字符串语法吧
注意 json 和 json5 格式的区别, 虽然都是字符串描述数据结构但是 json5 更加强大
rust
use std::net::Ipv4Addr;
use serde::{Deserialize, Serialize};
#[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]
serde = { version = "1.0.213", features = ["derive"] }
json5 = "0.4.1"
yaml
rust
use std::collections::HashMap;
use serde::{Deserialize, Serialize};
#[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.213", features = ["derive"] }
serde_yaml = "0.9.34"
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.213", features = ["derive"] }
toml = "0.8.19"