Rust 序列化库介绍
概述
序列化是将数据结构或对象转换为可存储或传输格式的过程,反序列化则是其逆过程。Rust 生态系统中有多个优秀的序列化库,本文将详细介绍主流的序列化库及其使用方法。
主流序列化库对比
库名 | 格式支持 | 性能 | 生态系统 | 特点 |
---|---|---|---|---|
Serde | JSON, YAML, TOML, XML 等 | 高 | 最丰富 | 事实标准,零成本抽象 |
bincode | 二进制 | 极高 | 好 | 紧凑的二进制格式 |
rmp-serde | MessagePack | 高 | 中等 | 高效的二进制 JSON |
postcard | 自定义二进制 | 极高 | 中等 | 无标准库,嵌入式友好 |
ciborium | CBOR | 高 | 中等 | RFC 7049 标准 |
Serde - Rust 序列化框架
1. 基础介绍
Serde 是 Rust 中最流行的序列化框架,提供了零成本抽象的序列化和反序列化功能。
添加依赖
[dependencies]
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0" # JSON 支持
serde_yaml = "0.9" # YAML 支持
toml = "0.8" # TOML 支持
2. 基础用法
简单结构体序列化
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug)]
struct User {
id: u32,
name: String,
email: String,
active: bool,
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let user = User {
id: 1,
name: "Alice".to_string(),
email: "alice@example.com".to_string(),
active: true,
};
// 序列化为 JSON
let json = serde_json::to_string(&user)?;
println!("JSON: {}", json);
// 从 JSON 反序列化
let user_from_json: User = serde_json::from_str(&json)?;
println!("User: {:?}", user_from_json);
Ok(())
}
复杂数据结构
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
#[derive(Serialize, Deserialize, Debug)]
struct Product {
id: u32,
name: String,
price: f64,
tags: Vec<String>,
metadata: HashMap<String, String>,
category: Category,
}
#[derive(Serialize, Deserialize, Debug)]
struct Category {
id: u32,
name: String,
parent_id: Option<u32>,
}
fn complex_serialization_example() -> Result<(), Box<dyn std::error::Error>> {
let mut metadata = HashMap::new();
metadata.insert("color".to_string(), "red".to_string());
metadata.insert("size".to_string(), "large".to_string());
let product = Product {
id: 101,
name: "Gaming Laptop".to_string(),
price: 1299.99,
tags: vec!["electronics".to_string(), "gaming".to_string()],
metadata,
category: Category {
id: 1,
name: "Computers".to_string(),
parent_id: None,
},
};
// 美化输出的 JSON
let json = serde_json::to_string_pretty(&product)?;
println!("{}", json);
Ok(())
}
3. Serde 属性和自定义
字段重命名和跳过
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug)]
struct ApiResponse {
#[serde(rename = "user_id")]
id: u32,
#[serde(rename = "full_name")]
name: String,
#[serde(skip_serializing_if = "Option::is_none")]
avatar_url: Option<String>,
#[serde(skip)]
internal_data: String,
#[serde(default)]
is_verified: bool,
}
fn attributes_example() -> Result<(), Box<dyn std::error::Error>> {
let response = ApiResponse {
id: 123,
name: "John Doe".to_string(),
avatar_url: None,
internal_data: "secret".to_string(),
is_verified: true,
};
let json = serde_json::to_string_pretty(&response)?;
println!("{}", json);
// 输出不包含 internal_data 和 avatar_url (因为是 None)
Ok(())
}
自定义序列化函数
use serde::{Deserialize, Serialize, Serializer, Deserializer};
use chrono::{DateTime, Utc, TimeZone};
#[derive(Serialize, Deserialize, Debug)]
struct Event {
name: String,
#[serde(
serialize_with = "serialize_datetime",
deserialize_with = "deserialize_datetime"
)]
created_at: DateTime<Utc>,
}
fn serialize_datetime<S>(dt: &DateTime<Utc>, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let timestamp = dt.timestamp();
serializer.serialize_i64(timestamp)
}
fn deserialize_datetime<'de, D>(deserializer: D) -> Result<DateTime<Utc>, D::Error>
where
D: Deserializer<'de>,
{
let timestamp = i64::deserialize(deserializer)?;
Ok(Utc.timestamp_opt(timestamp, 0).unwrap())
}
4. 枚举序列化
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug)]
#[serde(tag = "type")]
enum Message {
#[serde(rename = "text")]
Text { content: String },
#[serde(rename = "image")]
Image { url: String, caption: Option<String> },
#[serde(rename = "file")]
File { filename: String, size: u64 },
}
#[derive(Serialize, Deserialize, Debug)]
enum Status {
Pending,
#[serde(rename = "in_progress")]
InProgress,
Completed,
Failed(String),
}
fn enum_serialization_example() -> Result<(), Box<dyn std::error::Error>> {
let messages = vec![
Message::Text {
content: "Hello, world!".to_string(),
},
Message::Image {
url: "https://example.com/image.jpg".to_string(),
caption: Some("A beautiful sunset".to_string()),
},
Message::File {
filename: "document.pdf".to_string(),
size: 1024768,
},
];
for message in &messages {
let json = serde_json::to_string_pretty(message)?;
println!("{}\n", json);
}
let status = Status::Failed("Network timeout".to_string());
let status_json = serde_json::to_string(&status)?;
println!("Status: {}", status_json);
Ok(())
}
二进制序列化库
1. bincode
高性能的二进制序列化库,特别适合需要紧凑存储的场景。
[dependencies]
bincode = "1.3"
serde = { version = "1.0", features = ["derive"] }
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug, PartialEq)]
struct GameState {
player_id: u32,
position: (f32, f32, f32),
health: u8,
inventory: Vec<String>,
level: u16,
}
fn bincode_example() -> Result<(), Box<dyn std::error::Error>> {
let game_state = GameState {
player_id: 12345,
position: (100.5, 200.0, 50.25),
health: 85,
inventory: vec![
"sword".to_string(),
"health_potion".to_string(),
"key".to_string(),
],
level: 42,
};
// 序列化为二进制
let encoded = bincode::serialize(&game_state)?;
println!("二进制大小: {} bytes", encoded.len());
// 反序列化
let decoded: GameState = bincode::deserialize(&encoded)?;
println!("反序列化结果: {:?}", decoded);
assert_eq!(game_state, decoded);
// 与 JSON 大小比较
let json_size = serde_json::to_string(&game_state)?.len();
println!("JSON 大小: {} bytes", json_size);
println!("压缩比: {:.1}%", (encoded.len() as f64 / json_size as f64) * 100.0);
Ok(())
}
2. MessagePack (rmp-serde)
高效的二进制 JSON 格式。
[dependencies]
rmp-serde = "1.1"
serde = { version = "1.0", features = ["derive"] }
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug)]
struct ApiData {
users: Vec<User>,
total_count: u32,
page: u32,
}
#[derive(Serialize, Deserialize, Debug)]
struct User {
id: u32,
username: String,
email: String,
created_at: i64,
}
fn messagepack_example() -> Result<(), Box<dyn std::error::Error>> {
let data = ApiData {
users: vec![
User {
id: 1,
username: "alice".to_string(),
email: "alice@example.com".to_string(),
created_at: 1640995200,
},
User {
id: 2,
username: "bob".to_string(),
email: "bob@example.com".to_string(),
created_at: 1640995300,
},
],
total_count: 2,
page: 1,
};
// 序列化为 MessagePack
let packed = rmp_serde::to_vec(&data)?;
println!("MessagePack 大小: {} bytes", packed.len());
// 反序列化
let unpacked: ApiData = rmp_serde::from_slice(&packed)?;
println!("用户数量: {}", unpacked.users.len());
// 大小比较
let json_size = serde_json::to_string(&data)?.len();
println!("JSON 大小: {} bytes", json_size);
Ok(())
}
性能比较示例
use serde::{Deserialize, Serialize};
use std::time::Instant;
#[derive(Serialize, Deserialize, Debug, Clone)]
struct BenchmarkData {
numbers: Vec<i32>,
strings: Vec<String>,
nested: Vec<NestedData>,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
struct NestedData {
id: u32,
value: f64,
active: bool,
}
fn create_test_data() -> BenchmarkData {
BenchmarkData {
numbers: (0..1000).collect(),
strings: (0..100).map(|i| format!("string_{}", i)).collect(),
nested: (0..100)
.map(|i| NestedData {
id: i,
value: i as f64 * 3.14,
active: i % 2 == 0,
})
.collect(),
}
}
fn benchmark_serialization() -> Result<(), Box<dyn std::error::Error>> {
let data = create_test_data();
// JSON 序列化基准测试
let start = Instant::now();
let json_data = serde_json::to_vec(&data)?;
let json_time = start.elapsed();
// bincode 序列化基准测试
let start = Instant::now();
let bincode_data = bincode::serialize(&data)?;
let bincode_time = start.elapsed();
// MessagePack 序列化基准测试
let start = Instant::now();
let msgpack_data = rmp_serde::to_vec(&data)?;
let msgpack_time = start.elapsed();
println!("=== 序列化性能比较 ===");
println!("JSON: {:?} ({} bytes)", json_time, json_data.len());
println!("bincode: {:?} ({} bytes)", bincode_time, bincode_data.len());
println!("MessagePack: {:?} ({} bytes)", msgpack_time, msgpack_data.len());
// 反序列化基准测试
println!("\n=== 反序列化性能比较 ===");
let start = Instant::now();
let _: BenchmarkData = serde_json::from_slice(&json_data)?;
println!("JSON: {:?}", start.elapsed());
let start = Instant::now();
let _: BenchmarkData = bincode::deserialize(&bincode_data)?;
println!("bincode: {:?}", start.elapsed());
let start = Instant::now();
let _: BenchmarkData = rmp_serde::from_slice(&msgpack_data)?;
println!("MessagePack: {:?}", start.elapsed());
Ok(())
}
实际应用场景
1. Web API 响应
use serde::{Deserialize, Serialize};
use warp::Filter;
#[derive(Serialize, Deserialize)]
struct ApiResponse<T> {
success: bool,
data: Option<T>,
error: Option<String>,
timestamp: i64,
}
impl<T> ApiResponse<T> {
fn success(data: T) -> Self {
Self {
success: true,
data: Some(data),
error: None,
timestamp: chrono::Utc::now().timestamp(),
}
}
fn error(message: String) -> Self {
Self {
success: false,
data: None,
error: Some(message),
timestamp: chrono::Utc::now().timestamp(),
}
}
}
#[derive(Serialize, Deserialize)]
struct UserProfile {
id: u32,
username: String,
email: String,
avatar_url: Option<String>,
created_at: i64,
last_login: Option<i64>,
}
// Web API 端点示例
async fn get_user_profile(id: u32) -> Result<impl warp::Reply, warp::Rejection> {
// 模拟数据库查询
let user = UserProfile {
id,
username: format!("user_{}", id),
email: format!("user_{}@example.com", id),
avatar_url: Some("https://example.com/avatar.jpg".to_string()),
created_at: 1640995200,
last_login: Some(1672531200),
};
let response = ApiResponse::success(user);
Ok(warp::reply::json(&response))
}
2. 配置文件管理
use serde::{Deserialize, Serialize};
use std::fs;
#[derive(Serialize, Deserialize, Debug)]
struct AppConfig {
server: ServerConfig,
database: DatabaseConfig,
cache: CacheConfig,
logging: LoggingConfig,
}
#[derive(Serialize, Deserialize, Debug)]
struct ServerConfig {
host: String,
port: u16,
max_connections: u32,
timeout_seconds: u64,
}
#[derive(Serialize, Deserialize, Debug)]
struct DatabaseConfig {
url: String,
max_pool_size: u32,
connection_timeout: u64,
query_timeout: u64,
}
#[derive(Serialize, Deserialize, Debug)]
struct CacheConfig {
redis_url: String,
default_ttl: u64,
max_memory: String,
}
#[derive(Serialize, Deserialize, Debug)]
struct LoggingConfig {
level: String,
file_path: Option<String>,
max_file_size: String,
max_files: u32,
}
impl Default for AppConfig {
fn default() -> Self {
Self {
server: ServerConfig {
host: "127.0.0.1".to_string(),
port: 8080,
max_connections: 1000,
timeout_seconds: 30,
},
database: DatabaseConfig {
url: "postgresql://localhost/myapp".to_string(),
max_pool_size: 10,
connection_timeout: 30,
query_timeout: 60,
},
cache: CacheConfig {
redis_url: "redis://localhost:6379".to_string(),
default_ttl: 3600,
max_memory: "256mb".to_string(),
},
logging: LoggingConfig {
level: "info".to_string(),
file_path: Some("app.log".to_string()),
max_file_size: "10MB".to_string(),
max_files: 5,
},
}
}
}
impl AppConfig {
// 从 TOML 文件加载配置
pub fn from_toml_file(path: &str) -> Result<Self, Box<dyn std::error::Error>> {
let content = fs::read_to_string(path)?;
let config: AppConfig = toml::from_str(&content)?;
Ok(config)
}
// 保存配置到 TOML 文件
pub fn save_to_toml_file(&self, path: &str) -> Result<(), Box<dyn std::error::Error>> {
let content = toml::to_string_pretty(self)?;
fs::write(path, content)?;
Ok(())
}
// 从 JSON 文件加载配置
pub fn from_json_file(path: &str) -> Result<Self, Box<dyn std::error::Error>> {
let content = fs::read_to_string(path)?;
let config: AppConfig = serde_json::from_str(&content)?;
Ok(config)
}
// 从 YAML 文件加载配置
pub fn from_yaml_file(path: &str) -> Result<Self, Box<dyn std::error::Error>> {
let content = fs::read_to_string(path)?;
let config: AppConfig = serde_yaml::from_str(&content)?;
Ok(config)
}
}
fn config_management_example() -> Result<(), Box<dyn std::error::Error>> {
// 创建默认配置
let config = AppConfig::default();
// 保存为不同格式
config.save_to_toml_file("config.toml")?;
let json_content = serde_json::to_string_pretty(&config)?;
fs::write("config.json", json_content)?;
let yaml_content = serde_yaml::to_string(&config)?;
fs::write("config.yaml", yaml_content)?;
// 加载配置
let loaded_config = AppConfig::from_toml_file("config.toml")?;
println!("加载的配置: {:#?}", loaded_config);
Ok(())
}
3. 游戏状态序列化
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
#[derive(Serialize, Deserialize, Debug, Clone)]
struct GameSave {
version: String,
player: Player,
world: World,
inventory: Inventory,
quests: Vec<Quest>,
settings: GameSettings,
save_time: i64,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
struct Player {
name: String,
level: u32,
experience: u64,
position: Position,
stats: PlayerStats,
skills: HashMap<String, u32>,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
struct Position {
x: f64,
y: f64,
z: f64,
map_id: String,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
struct PlayerStats {
health: u32,
max_health: u32,
mana: u32,
max_mana: u32,
strength: u32,
agility: u32,
intelligence: u32,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
struct World {
seed: u64,
explored_areas: Vec<String>,
unlocked_locations: Vec<String>,
world_events: Vec<WorldEvent>,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
struct WorldEvent {
id: String,
event_type: String,
timestamp: i64,
data: HashMap<String, String>,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
struct Inventory {
items: Vec<Item>,
max_slots: u32,
gold: u64,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
struct Item {
id: String,
name: String,
quantity: u32,
item_type: ItemType,
properties: HashMap<String, String>,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
enum ItemType {
Weapon { damage: u32, durability: u32 },
Armor { defense: u32, durability: u32 },
Consumable { effect: String },
Material,
Key { area_id: String },
}
#[derive(Serialize, Deserialize, Debug, Clone)]
struct Quest {
id: String,
title: String,
description: String,
status: QuestStatus,
objectives: Vec<QuestObjective>,
rewards: Vec<QuestReward>,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
enum QuestStatus {
NotStarted,
InProgress,
Completed,
Failed,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
struct QuestObjective {
id: String,
description: String,
completed: bool,
progress: u32,
target: u32,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
struct QuestReward {
reward_type: String,
amount: u32,
item_id: Option<String>,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
struct GameSettings {
graphics: GraphicsSettings,
audio: AudioSettings,
controls: ControlSettings,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
struct GraphicsSettings {
resolution: (u32, u32),
fullscreen: bool,
vsync: bool,
quality: String,
fps_limit: Option<u32>,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
struct AudioSettings {
master_volume: f32,
music_volume: f32,
sfx_volume: f32,
voice_volume: f32,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
struct ControlSettings {
key_bindings: HashMap<String, String>,
mouse_sensitivity: f32,
invert_y: bool,
}
impl GameSave {
// 创建新的游戏存档
pub fn new(player_name: String) -> Self {
let mut skills = HashMap::new();
skills.insert("combat".to_string(), 1);
skills.insert("magic".to_string(), 1);
skills.insert("crafting".to_string(), 1);
let mut key_bindings = HashMap::new();
key_bindings.insert("move_forward".to_string(), "W".to_string());
key_bindings.insert("move_backward".to_string(), "S".to_string());
key_bindings.insert("move_left".to_string(), "A".to_string());
key_bindings.insert("move_right".to_string(), "D".to_string());
key_bindings.insert("jump".to_string(), "Space".to_string());
Self {
version: "1.0.0".to_string(),
player: Player {
name: player_name,
level: 1,
experience: 0,
position: Position {
x: 0.0,
y: 0.0,
z: 0.0,
map_id: "starting_village".to_string(),
},
stats: PlayerStats {
health: 100,
max_health: 100,
mana: 50,
max_mana: 50,
strength: 10,
agility: 10,
intelligence: 10,
},
skills,
},
world: World {
seed: 12345678,
explored_areas: vec!["starting_village".to_string()],
unlocked_locations: vec!["starting_village".to_string()],
world_events: vec![],
},
inventory: Inventory {
items: vec![
Item {
id: "starter_sword".to_string(),
name: "Rusty Sword".to_string(),
quantity: 1,
item_type: ItemType::Weapon {
damage: 10,
durability: 50,
},
properties: HashMap::new(),
},
],
max_slots: 20,
gold: 100,
},
quests: vec![],
settings: GameSettings {
graphics: GraphicsSettings {
resolution: (1920, 1080),
fullscreen: false,
vsync: true,
quality: "high".to_string(),
fps_limit: Some(60),
},
audio: AudioSettings {
master_volume: 1.0,
music_volume: 0.8,
sfx_volume: 1.0,
voice_volume: 1.0,
},
controls: ControlSettings {
key_bindings,
mouse_sensitivity: 1.0,
invert_y: false,
},
},
save_time: chrono::Utc::now().timestamp(),
}
}
// 保存游戏(支持多种格式)
pub fn save_to_file(&self, path: &str, format: SaveFormat) -> Result<(), Box<dyn std::error::Error>> {
match format {
SaveFormat::Json => {
let content = serde_json::to_string_pretty(self)?;
std::fs::write(path, content)?;
},
SaveFormat::Binary => {
let content = bincode::serialize(self)?;
std::fs::write(path, content)?;
},
SaveFormat::MessagePack => {
let content = rmp_serde::to_vec(self)?;
std::fs::write(path, content)?;
},
}
Ok(())
}
// 从文件加载游戏
pub fn load_from_file(path: &str, format: SaveFormat) -> Result<Self, Box<dyn std::error::Error>> {
match format {
SaveFormat::Json => {
let content = std::fs::read_to_string(path)?;
let save: GameSave = serde_json::from_str(&content)?;
Ok(save)
},
SaveFormat::Binary => {
let content = std::fs::read(path)?;
let save: GameSave = bincode::deserialize(&content)?;
Ok(save)
},
SaveFormat::MessagePack => {
let content = std::fs::read(path)?;
let save: GameSave = rmp_serde::from_slice(&content)?;
Ok(save)
},
}
}
}
#[derive(Debug)]
enum SaveFormat {
Json,
Binary,
MessagePack,
}
fn game_save_example() -> Result<(), Box<dyn std::error::Error>> {
// 创建新游戏存档
let mut game_save = GameSave::new("Alice".to_string());
// 模拟游戏进程
game_save.player.level = 5;
game_save.player.experience = 1250;
game_save.player.position.x = 100.5;
game_save.player.position.y = 200.0;
// 添加任务
game_save.quests.push(Quest {
id: "kill_goblins".to_string(),
title: "Goblin Hunt".to_string(),
description: "Kill 10 goblins in the forest".to_string(),
status: QuestStatus::InProgress,
objectives: vec![
QuestObjective {
id: "kill_count".to_string(),
description: "Kill goblins".to_string(),
completed: false,
progress: 7,
target: 10,
}
],
rewards: vec![
QuestReward {
reward_type: "experience".to_string(),
amount: 500,
item_id: None,
},
QuestReward {
reward_type: "gold".to_string(),
amount: 100,
item_id: None,
},
],
});
// 保存为不同格式并比较大小
println!("=== 保存游戏存档 ===");
game_save.save_to_file("save_game.json", SaveFormat::Json)?;
game_save.save_to_file("save_game.bin", SaveFormat::Binary)?;
game_save.save_to_file("save_game.msgpack", SaveFormat::MessagePack)?;
// 比较文件大小
let json_size = std::fs::metadata("save_game.json")?.len();
let binary_size = std::fs::metadata("save_game.bin")?.len();
let msgpack_size = std::fs::metadata("save_game.msgpack")?.len();
println!("JSON 格式大小: {} bytes", json_size);
println!("Binary 格式大小: {} bytes", binary_size);
println!("MessagePack 格式大小: {} bytes", msgpack_size);
// 测试加载速度
use std::time::Instant;
let start = Instant::now();
let _json_load = GameSave::load_from_file("save_game.json", SaveFormat::Json)?;
let json_time = start.elapsed();
let start = Instant::now();
let _binary_load = GameSave::load_from_file("save_game.bin", SaveFormat::Binary)?;
let binary_time = start.elapsed();
let start = Instant::now();
let _msgpack_load = GameSave::load_from_file("save_game.msgpack", SaveFormat::MessagePack)?;
let msgpack_time = start.elapsed();
println!("\n=== 加载速度比较 ===");
println!("JSON 加载时间: {:?}", json_time);
println!("Binary 加载时间: {:?}", binary_time);
println!("MessagePack 加载时间: {:?}", msgpack_time);
Ok(())
}
序列化性能优化
1. 零拷贝反序列化
use serde::{Deserialize, Serialize};
// 使用借用字符串进行零拷贝反序列化
#[derive(Deserialize, Debug)]
struct BorrowedData<'a> {
#[serde(borrow)]
name: &'a str,
#[serde(borrow)]
description: &'a str,
id: u32,
active: bool,
}
#[derive(Serialize, Debug)]
struct OwnedData {
name: String,
description: String,
id: u32,
active: bool,
}
fn zero_copy_example() -> Result<(), Box<dyn std::error::Error>> {
let owned_data = OwnedData {
name: "Product Name".to_string(),
description: "This is a detailed product description".to_string(),
id: 12345,
active: true,
};
// 序列化
let json = serde_json::to_string(&owned_data)?;
println!("JSON: {}", json);
// 零拷贝反序列化
let borrowed_data: BorrowedData = serde_json::from_str(&json)?;
println!("借用数据: {:?}", borrowed_data);
// 验证字符串确实是借用的
println!("原始 JSON 地址: {:p}", json.as_ptr());
println!("借用 name 地址: {:p}", borrowed_data.name.as_ptr());
Ok(())
}
2. 自定义序列化器提升性能
use serde::{Deserialize, Serialize, Serializer, Deserializer};
use std::fmt;
// 自定义序列化大数组
#[derive(Debug)]
struct LargeArray {
data: Vec<f64>,
}
impl Serialize for LargeArray {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
use serde::ser::SerializeSeq;
let mut seq = serializer.serialize_seq(Some(self.data.len()))?;
for element in &self.data {
// 只序列化非零值以节省空间
if *element != 0.0 {
seq.serialize_element(element)?;
} else {
seq.serialize_element(&0i8)?; // 使用更小的类型
}
}
seq.end()
}
}
// 压缩整数序列化
fn serialize_compressed_int<S>(value: &u64, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
// 如果值小于 u32::MAX,使用 u32 序列化以节省空间
if *value <= u32::MAX as u64 {
serializer.serialize_u32(*value as u32)
} else {
serializer.serialize_u64(*value)
}
}
#[derive(Serialize, Deserialize)]
struct OptimizedStruct {
#[serde(serialize_with = "serialize_compressed_int")]
large_number: u64,
#[serde(skip_serializing_if = "Vec::is_empty")]
optional_data: Vec<String>,
#[serde(skip_serializing_if = "Option::is_none")]
metadata: Option<String>,
}
3. 流式序列化处理大数据
use serde::{Deserialize, Serialize};
use serde_json::{Deserializer, StreamDeserializer};
use std::io::{BufReader, BufWriter, Write};
use std::fs::File;
#[derive(Serialize, Deserialize, Debug)]
struct Record {
id: u64,
timestamp: i64,
value: f64,
category: String,
}
fn stream_processing_example() -> Result<(), Box<dyn std::error::Error>> {
// 生成大量测试数据
let records: Vec<Record> = (0..100000)
.map(|i| Record {
id: i,
timestamp: 1640995200 + i as i64,
value: (i as f64) * 3.14159,
category: format!("category_{}", i % 10),
})
.collect();
// 流式写入文件
let file = File::create("large_data.jsonl")?;
let mut writer = BufWriter::new(file);
println!("开始流式写入...");
let start = std::time::Instant::now();
for record in &records {
serde_json::to_writer(&mut writer, record)?;
writer.write_all(b"\n")?;
}
writer.flush()?;
let write_time = start.elapsed();
println!("写入完成,耗时: {:?}", write_time);
// 流式读取和处理
let file = File::open("large_data.jsonl")?;
let reader = BufReader::new(file);
println!("开始流式读取...");
let start = std::time::Instant::now();
let mut count = 0;
let mut sum = 0.0;
for line in std::io::BufRead::lines(reader) {
let line = line?;
let record: Record = serde_json::from_str(&line)?;
sum += record.value;
count += 1;
if count % 10000 == 0 {
println!("已处理 {} 条记录", count);
}
}
let read_time = start.elapsed();
println!("读取完成,耗时: {:?}", read_time);
println!("总计: {} 条记录,平均值: {:.2}", count, sum / count as f64);
Ok(())
}
错误处理最佳实践
1. 自定义错误类型
use serde::{Deserialize, Serialize};
use thiserror::Error;
#[derive(Error, Debug)]
pub enum SerializationError {
#[error("JSON 序列化错误: {0}")]
JsonError(#[from] serde_json::Error),
#[error("Binary 序列化错误: {0}")]
BincodeError(#[from] bincode::Error),
#[error("文件 I/O 错误: {0}")]
IoError(#[from] std::io::Error),
#[error("数据验证错误: {message}")]
ValidationError { message: String },
#[error("版本不兼容: 期望 {expected}, 实际 {actual}")]
VersionMismatch { expected: String, actual: String },
}
type Result<T> = std::result::Result<T, SerializationError>;
#[derive(Serialize, Deserialize, Debug)]
struct VersionedData {
version: String,
data: serde_json::Value,
}
impl VersionedData {
const CURRENT_VERSION: &'static str = "1.0";
pub fn new(data: serde_json::Value) -> Self {
Self {
version: Self::CURRENT_VERSION.to_string(),
data,
}
}
pub fn validate_version(&self) -> Result<()> {
if self.version != Self::CURRENT_VERSION {
return Err(SerializationError::VersionMismatch {
expected: Self::CURRENT_VERSION.to_string(),
actual: self.version.clone(),
});
}
Ok(())
}
pub fn save_to_file(&self, path: &str) -> Result<()> {
self.validate_version()?;
let content = serde_json::to_string_pretty(self)?;
std::fs::write(path, content)?;
Ok(())
}
pub fn load_from_file(path: &str) -> Result<Self> {
let content = std::fs::read_to_string(path)?;
let data: VersionedData = serde_json::from_str(&content)?;
data.validate_version()?;
Ok(data)
}
}
2. 安全的序列化验证
use serde::{Deserialize, Serialize, Deserializer};
fn validate_email<'de, D>(deserializer: D) -> std::result::Result<String, D::Error>
where
D: Deserializer<'de>,
{
let email = String::deserialize(deserializer)?;
if email.contains('@') && email.contains('.') {
Ok(email)
} else {
Err(serde::de::Error::custom("无效的邮箱格式"))
}
}
fn validate_age<'de, D>(deserializer: D) -> std::result::Result<u8, D::Error>
where
D: Deserializer<'de>,
{
let age = u8::deserialize(deserializer)?;
if age > 0 && age < 150 {
Ok(age)
} else {
Err(serde::de::Error::custom("年龄必须在 1-149 之间"))
}
}
#[derive(Serialize, Deserialize, Debug)]
struct ValidatedUser {
#[serde(deserialize_with = "validate_email")]
email: String,
#[serde(deserialize_with = "validate_age")]
age: u8,
name: String,
}
fn validation_example() -> Result<(), Box<dyn std::error::Error>> {
let valid_json = r#"
{
"email": "user@example.com",
"age": 25,
"name": "Alice"
}"#;
let invalid_json = r#"
{
"email": "invalid-email",
"age": 200,
"name": "Bob"
}"#;
// 有效数据
match serde_json::from_str::<ValidatedUser>(valid_json) {
Ok(user) => println!("有效用户: {:?}", user),
Err(e) => println!("验证失败: {}", e),
}
// 无效数据
match serde_json::from_str::<ValidatedUser>(invalid_json) {
Ok(user) => println!("用户: {:?}", user),
Err(e) => println!("验证失败: {}", e),
}
Ok(())
}
实际项目集成示例
// main.rs - 完整的序列化示例项目
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
mod config;
mod game;
mod api;
mod utils;
use config::AppConfig;
use game::GameSave;
use api::ApiResponse;
fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("=== Rust 序列化库使用示例 ===\n");
// 1. 配置文件管理
println!("1. 配置文件管理示例:");
config_demo()?;
// 2. 游戏存档序列化
println!("\n2. 游戏存档序列化示例:");
game_demo()?;
// 3. API 响应处理
println!("\n3. API 响应处理示例:");
api_demo()?;
// 4. 性能基准测试
println!("\n4. 性能基准测试:");
benchmark_demo()?;
// 5. 错误处理示例
println!("\n5. 错误处理示例:");
error_handling_demo()?;
Ok(())
}
fn config_demo() -> Result<(), Box<dyn std::error::Error>> {
let config = AppConfig::default();
config.save_to_toml_file("example_config.toml")?;
let loaded_config = AppConfig::from_toml_file("example_config.toml")?;
println!("配置已保存并重新加载成功");
println!("服务器端口: {}", loaded_config.server.port);
println!("数据库URL: {}", loaded_config.database.url);
Ok(())
}
fn game_demo() -> Result<(), Box<dyn std::error::Error>> {
let game_save = GameSave::new("TestPlayer".to_string());
// 保存为不同格式
game_save.save_to_file("game_save.json", game::SaveFormat::Json)?;
game_save.save_to_file("game_save.bin", game::SaveFormat::Binary)?;
game_save.save_to_file("game_save.msgpack", game::SaveFormat::MessagePack)?;
// 比较文件大小
let json_size = std::fs::metadata("game_save.json")?.len();
let binary_size = std::fs::metadata("game_save.bin")?.len();
let msgpack_size = std::fs::metadata("game_save.msgpack")?.len();
println!("游戏存档文件大小比较:");
println!(" JSON: {} bytes", json_size);
println!(" Binary: {} bytes ({:.1}% of JSON)",
binary_size, (binary_size as f64 / json_size as f64) * 100.0);
println!(" MessagePack: {} bytes ({:.1}% of JSON)",
msgpack_size, (msgpack_size as f64 / json_size as f64) * 100.0);
Ok(())
}
fn api_demo() -> Result<(), Box<dyn std::error::Error>> {
// 模拟 API 响应
let user_data = serde_json::json!({
"id": 123,
"username": "alice",
"email": "alice@example.com",
"profile": {
"avatar": "https://example.com/avatar.jpg",
"bio": "Software developer"
}
});
let success_response = ApiResponse::success(user_data);
let error_response = ApiResponse::<()>::error("用户未找到".to_string());
println!("成功响应: {}", serde_json::to_string_pretty(&success_response)?);
println!("错误响应: {}", serde_json::to_string_pretty(&error_response)?);
Ok(())
}
fn benchmark_demo() -> Result<(), Box<dyn std::error::Error>> {
use std::time::Instant;
// 创建测试数据
let test_data: Vec<HashMap<String, serde_json::Value>> = (0..1000)
.map(|i| {
let mut map = HashMap::new();
map.insert("id".to_string(), serde_json::Value::Number(i.into()));
map.insert("name".to_string(), serde_json::Value::String(format!("user_{}", i)));
map.insert("score".to_string(), serde_json::Value::Number((i as f64 * 3.14).into()));
map.insert("active".to_string(), serde_json::Value::Bool(i % 2 == 0));
map
})
.collect();
// JSON 序列化基准
let start = Instant::now();
let json_data = serde_json::to_vec(&test_data)?;
let json_serialize_time = start.elapsed();
let start = Instant::now();
let _: Vec<HashMap<String, serde_json::Value>> = serde_json::from_slice(&json_data)?;
let json_deserialize_time = start.elapsed();
// bincode 序列化基准
let start = Instant::now();
let binary_data = bincode::serialize(&test_data)?;
let binary_serialize_time = start.elapsed();
let start = Instant::now();
let _: Vec<HashMap<String, serde_json::Value>> = bincode::deserialize(&binary_data)?;
let binary_deserialize_time = start.elapsed();
// MessagePack 序列化基准
let start = Instant::now();
let msgpack_data = rmp_serde::to_vec(&test_data)?;
let msgpack_serialize_time = start.elapsed();
let start = Instant::now();
let _: Vec<HashMap<String, serde_json::Value>> = rmp_serde::from_slice(&msgpack_data)?;
let msgpack_deserialize_time = start.elapsed();
println!("性能基准测试结果 (1000 条记录):");
println!("格式 | 序列化时间 | 反序列化时间 | 大小 (bytes)");
println!("----------- | ------------ | ------------ | ------------");
println!("JSON | {:>10?} | {:>10?} | {:>10}",
json_serialize_time, json_deserialize_time, json_data.len());
println!("bincode | {:>10?} | {:>10?} | {:>10}",
binary_serialize_time, binary_deserialize_time, binary_data.len());
println!("MessagePack | {:>10?} | {:>10?} | {:>10}",
msgpack_serialize_time, msgpack_deserialize_time, msgpack_data.len());
Ok(())
}
fn error_handling_demo() -> Result<(), Box<dyn std::error::Error>> {
// 测试无效 JSON
let invalid_json = r#"{"name": "test", "age": "invalid_age"}"#;
#[derive(Deserialize)]
struct TestStruct {
name: String,
age: u32,
}
match serde_json::from_str::<TestStruct>(invalid_json) {
Ok(_) => println!("解析成功"),
Err(e) => {
println!("JSON 解析错误: {}", e);
println!("错误位置: 行 {}, 列 {}", e.line(), e.column());
}
}
// 测试版本兼容性
let old_version_data = r#"{"version": "0.9", "data": {"test": true}}"#;
match VersionedData::load_from_str(old_version_data) {
Ok(_) => println!("版本兼容"),
Err(e) => println!("版本不兼容: {}", e),
}
Ok(())
}
// 辅助结构体用于演示
#[derive(Serialize, Deserialize)]
struct VersionedData {
version: String,
data: serde_json::Value,
}
impl VersionedData {
fn load_from_str(s: &str) -> Result<Self, String> {
let data: VersionedData = serde_json::from_str(s)
.map_err(|e| format!("JSON 解析错误: {}", e))?;
if data.version != "1.0" {
return Err(format!("不支持的版本: {}", data.version));
}
Ok(data)
}
}
总结与最佳实践
选择合适的序列化库
-
Serde + serde_json:
- 适用于 Web API、配置文件
- 可读性好,调试友好
- 生态系统丰富
-
bincode:
- 适用于高性能场景、游戏存档
- 文件大小最小
- 序列化/反序列化速度最快
-
MessagePack:
- 适用于网络传输、微服务通信
- 平衡了大小和性能
- 跨语言兼容性好
性能优化建议
- 减少内存分配:
// 使用借用而非拥有
#[derive(Deserialize)]
struct BorrowedData<'a> {
#[serde(borrow)]
name: &'a str,
}
- 跳过不必要的字段:
#[derive(Serialize)]
struct OptimizedStruct {
#[serde(skip_serializing_if = "Option::is_none")]
optional_field: Option<String>,
}
- 使用流式处理大数据:
// 避免将大型数据集完全加载到内存
for line in BufRead::lines(reader) {
let record: Record = serde_json::from_str(&line?)?;
process_record(record);
}
错误处理建议
- 使用自定义错误类型
- 验证输入数据
- 处理版本兼容性
- 提供有意义的错误信息
安全性考虑
- 限制反序列化的数据大小
- 验证输入数据的合法性
- 避免反序列化不受信任的数据
- 使用类型安全的反序列化
通过合理选择和使用这些序列化库,可以在 Rust 项目中实现高效、安全的数据序列化和反序列化功能。
祺洛管理系统介绍
祺洛是一个 Rust 企业级快速开发平台,基于(Rust、 Axum、Sea-orm、Jwt、Vue),内置模块如:部门管理、角色用户、菜单及按钮授权、数据权限、系统参数、日志管理等。在线定时任务配置;支持集群,支持多数据源,支持分布式部署。
🌐 官方网站: https://www.qiluo.vip/
让企业级应用开发更简单、更高效、更安全