外观
第 1 节:serde——结构体与 JSON 之间
一句话:给结构体加上 #[derive(Serialize, Deserialize)],它就能变成 JSON、又能从 JSON 变回来。配置文件、网络请求、数据库记录……真实项目里 JSON 无处不在,serde 是 Rust 生态的"基础设施之王"。
安装
bash
cargo add serde --features derive
cargo add serde_json基本用法:两行魔法 ⭐
rust
use serde::{Deserialize, Serialize};
#[derive(Debug, Serialize, Deserialize, PartialEq)]
struct Pet {
name: String,
age: u32,
#[serde(default)]
nickname: Option<String>,
}
fn main() {
// 结构体 -> JSON
let pet = Pet {
name: String::from("小咪"),
age: 2,
nickname: Some(String::from("咪咪")),
};
let json = serde_json::to_string_pretty(&pet).expect("序列化失败");
// {
// "name": "小咪",
// "age": 2,
// "nickname": "咪咪"
// }
// JSON -> 结构体
let input = r#"{"name": "旺财", "age": 3}"#;
let parsed: Pet = serde_json::from_str(input).expect("反序列化失败");
}三个要点:
derive两行,自动实现:Serialize(变成 JSON)、Deserialize(从 JSON 变回)——不用手写任何解析代码- 字段名默认和 JSON 键一一对应
#[serde(default)]:JSON 里缺这个字段时,用默认值(这里nickname缺了就给None)——处理"可选字段"的标准姿势
高频场景
读写配置文件(第 8 章手写解析的"工业级版"):
rust
use std::fs;
#[derive(Serialize, Deserialize)]
struct Config {
host: String,
port: u16,
#[serde(default = "default_workers")]
workers: u32,
}
fn default_workers() -> u32 {
4
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
// 读
let text = fs::read_to_string("config.json")?;
let config: Config = serde_json::from_str(&text)?;
println!("{}:{}", config.host, config.port);
// 写
let out = serde_json::to_string_pretty(&config)?;
fs::write("config.json", out)?;
Ok(())
}#[serde(default = "函数名")]:缺字段时调用指定函数给默认值——旧配置升级、新增字段不炸。
动态 JSON(结构不确定):用 serde_json::Value:
rust
let value: serde_json::Value =
serde_json::from_str(r#"{"name": "小海马", "age": 1}"#)?;
println!("{} 岁", value["age"]); // 下标取值,缺失给 Null
println!("{:?}", value["age"].as_u64()); // 类型转换,失败给 None常见误用与坑
- 字段名要对上:JSON 是
user_name,结构体是username→ 反序列化失败。用#[serde(rename = "user_name")]或统一命名 Option字段:不加#[serde(default)],JSON 缺它就报错(不是给 None)——"可选"必须显式声明to_string_pretty才有换行:调试日志用 pretty,线上传输用to_string(紧凑,省带宽)- 数字溢出:JSON 的
1e10塞进u32会失败——大数用u64/i64/f64 - 未知字段默认忽略:JSON 多出来的键不会报错(想严格?加
#[serde(deny_unknown_fields)])
别手写解析
看到"手写 split/parse 解析配置文件"(第 8 章那种),先想想 serde——结构体一变,解析代码自动跟着变,永远不会"结构体和解析对不上"。