Rust基础之 JSON

在 Rust 中,处理 JSON 最常用且推荐的库是 serde 配合 serde_jsonserde 是一个高效的序列化 / 反序列化框架,而 serde_json 则是其针对 JSON 格式的实现。它们支持自动派生序列化 / 反序列化逻辑,处理复杂结构非常方便。

一:核心库介绍

  • serde :Rust 生态中最流行的序列化 / 反序列化框架,支持多种数据格式(不仅限于 JSON)。通过 derive 特性可以自动为结构体生成序列化 / 反序列化代码。
  • serde_jsonserde 的 JSON 实现,提供了 to_string/from_str 等方法处理 JSON 数据。

关键概念与用法

  1. 序列化(Serialization)

    • 将 Rust 数据结构转换为 JSON 字符串

    • 核心方法:

      • serde_json::to_string(&data):生成紧凑的 JSON
      • serde_json::to_string_pretty(&data):生成带缩进的易读 JSON
      • serde_json::to_value(&data):转换为可操作的 JsonValue
  2. 反序列化(Deserialization)

    • 将 JSON 字符串转换为 Rust 数据结构
    • 核心方法:serde_json::from_str::<T>(json_str)
    • 支持强类型转换(如转换为 User 结构体)和动态转换(转换为 JsonValue
  3. 自动派生特性

    • 通过 #[derive(Serialize, Deserialize)] 为结构体自动实现序列化 / 反序列化逻辑
    • 支持大多数 Rust 基本类型和标准库类型(VecOptionHashMap 等)
  4. 处理可选字段

    • 使用 Option<T> 表示可能存在或不存在的字段
    • 当 JSON 中缺少该字段时,会被反序列化为 None
  5. 动态 JSON 处理

    • 使用 serde_json::Value(别名 JsonValue)处理结构未知的 JSON
    • 支持通过索引(json_value["field"])访问字段,通过 as_* 方法转换类型
  6. 错误处理

    • 序列化 / 反序列化操作返回 Result 类型,需要处理可能的错误
    • 常见错误类型:JSON 格式错误、类型不匹配、缺少必要字段等

运行与测试

代码: 1.添加依赖库Cargo.toml

toml 复制代码
[dependencies]
serde = { version = "1.0", features = ["derive"] }  # 核心序列化库,启用derive特性
serde_json = "1.0"  # JSON格式支持

2.代码

rust 复制代码
use serde::{Serialize, Deserialize};
use serde_json::Value as JsonValue;
use std::error::Error;

// 1. 定义需要序列化/反序列化的结构体
// 使用derive自动实现Serialize和Deserialize trait
#[derive(Debug, Serialize, Deserialize, PartialEq)]
struct User {
    id: u64,
    name: String,
    email: Option<String>,  // 可选字段,JSON中可能不存在
    is_active: bool,
    roles: Vec<String>,
    metadata: Option<serde_json::Value>,  // 灵活的JSON值类型
}

#[derive(Debug, Serialize, Deserialize)]
struct ApiResponse {
    status: String,
    code: u16,
    data: Option<User>,  // 可能包含User对象
    message: String,
}

// 2. JSON序列化示例
fn serialization_demo() -> Result<(), Box<dyn Error>> {
    println!("=== 序列化示例 ===");

    // 创建一个User实例
    let user = User {
        id: 1001,
        name: "Alice Smith".to_string(),
        email: Some("alice@example.com".to_string()),
        is_active: true,
        roles: vec!["admin".to_string(), "user".to_string()],
        metadata: Some(serde_json::json!({
            "last_login": "2023-10-01T12:00:00Z",
            "preferences": {
                "theme": "dark",
                "notifications": true
            }
        })),
    };

    // 序列化为JSON字符串(带缩进的美观格式)
    let pretty_json = serde_json::to_string_pretty(&user)?;
    println!("User对象序列化为JSON:\n{}", pretty_json);

    // 序列化为紧凑的JSON字符串
    let compact_json = serde_json::to_string(&user)?;
    println!("\n紧凑格式JSON:\n{}", compact_json);

    // 序列化为JSON值(可操作的JSON对象)
    let json_value = serde_json::to_value(&user)?;
    println!("\nJSON值的name字段: {}", json_value["name"]);

    Ok(())
}

// 3. JSON反序列化示例
fn deserialization_demo() -> Result<(), Box<dyn Error>> {
    println!("\n=== 反序列化示例 ===");

    // 示例JSON字符串
    let json_str = r#"
    {
        "id": 1002,
        "name": "Bob Johnson",
        "is_active": false,
        "roles": ["user"],
        "metadata": {
            "last_login": "2023-09-15T08:30:00Z"
        }
    }
    "#;

    // 将JSON字符串反序列化为User对象
    let user: User = serde_json::from_str(json_str)?;
    println!("从JSON反序列化的User对象: {:?}", user);

    // 处理包含可选字段的情况
    println!("用户邮箱: {:?}", user.email);  // 这里是None,因为JSON中没有email字段

    // 反序列化为动态JSON值(未知结构时使用)
    let json_value: JsonValue = serde_json::from_str(json_str)?;
    println!("\n动态访问JSON字段:");
    println!("姓名: {}", json_value["name"].as_str().unwrap_or("未知"));
    println!("是否活跃: {}", json_value["is_active"].as_bool().unwrap_or(false));

    // 访问嵌套字段
    if let Some(metadata) = json_value["metadata"].as_object() {
        println!("最后登录时间: {}", metadata["last_login"].as_str().unwrap_or("未知"));
    }

    Ok(())
}

// 4. 处理API响应示例
fn api_response_demo() -> Result<(), Box<dyn Error>> {
    println!("\n=== API响应处理示例 ===");

    // 模拟API返回的JSON响应
    let api_json = r#"
    {
        "status": "success",
        "code": 200,
        "data": {
            "id": 1003,
            "name": "Charlie Brown",
            "email": "charlie@example.com",
            "is_active": true,
            "roles": ["moderator", "user"],
            "metadata": null
        },
        "message": "操作成功"
    }
    "#;

    // 反序列化为ApiResponse结构体
    let response: ApiResponse = serde_json::from_str(api_json)?;
    println!("API响应状态: {}", response.status);
    println!("API响应代码: {}", response.code);

    // 处理可能存在的数据字段
    if let Some(user) = &response.data {
        println!("API返回的用户: {}", user.name);
    }

    // 序列化API响应
    let response_json = serde_json::to_string_pretty(&response)?;
    println!("\nAPI响应序列化:\n{}", response_json);

    Ok(())
}

// 5. 错误处理示例
fn error_handling_demo() {
    println!("\n=== 错误处理示例 ===");

    // 无效的JSON
    let invalid_json = r#"{"id": 1004, "name": "David" "#;

    match serde_json::from_str::<User>(invalid_json) {
        Ok(user) => println!("成功反序列化: {:?}", user),
        Err(e) => println!("JSON解析错误: {}", e),
    }

    // 类型不匹配的JSON
    let type_mismatch_json = r#"{"id": "not_a_number", "name": "Eve"}"#;

    match serde_json::from_str::<User>(type_mismatch_json) {
        Ok(user) => println!("成功反序列化: {:?}", user),
        Err(e) => println!("类型不匹配错误: {}", e),
    }
}

fn main() -> Result<(), Box<dyn Error>> {
    // 运行各个示例
    serialization_demo()?;
    deserialization_demo()?;
    api_response_demo()?;
    error_handling_demo();

    Ok(())
}
  1. 确保 Cargo.toml 中添加了依赖
  2. 运行程序:cargo run
  3. 观察输出,了解序列化 / 反序列化的过程和结果

二:最佳实践

  1. 优先使用强类型:对于结构已知的 JSON,定义对应的结构体并使用自动派生,类型安全且性能更好

  2. 合理使用可选字段 :用 Option<T> 处理可能缺失的字段

  3. 处理动态结构 :对于结构不确定的 JSON,使用 JsonValue 进行动态处理

  4. 错误处理 :始终处理序列化 / 反序列化可能产生的错误,避免使用 unwrap()

这种处理方式兼顾了类型安全、性能和灵活性,是 Rust 中处理 JSON 的标准方案,广泛应用于 API 交互、配置文件处理、数据存储等场景。

相关推荐
唐天一6 小时前
Rust默认规则之总结及其代码示例
后端
池易6 小时前
Go 语言的现代化 WebSocket 开发利器
后端
命中的缘分6 小时前
Spring Boot 和 Spring Cloud 的原理和区别
spring boot·后端·spring cloud
IT_陈寒6 小时前
10个Vite配置技巧让你的开发效率提升200%,第7个绝了!
前端·人工智能·后端
趙卋傑7 小时前
Spring原理
java·后端·spring
唐天一7 小时前
Rust基础之异常
后端
毕设源码-赖学姐7 小时前
【开题答辩全过程】以 基于Spring Boot的网上家庭烹饪学习系统的设计与实现为例,包含答辩的问题和答案
spring boot·后端·学习
Moonbit7 小时前
MoonBit Pearls Vol.08: MoonBit 与 Python集成指南
后端·python·程序员
刘祯昊7 小时前
中望CAD二次开发(一)——开发环境配置
后端·c#