Rust结构体的JSON序列化和反序列化

一个JSON的序列化问题

与人聊天时偶然问到一个问题:“给定任意一个(C/C++)结构体,如何实现其JSON的序列化和反序列化,而不用专门编写相应的序列化、反序列化实现代码?”我摇摇头,表示不知如何实现这一功能;现在我也认为,这一功能对于C/C++,是不可能自动化实现的。不过对于其他的静态编译型编程语言,如Golang/Rust等,这一功能则相对容易实现。与Golang的反射机制(Reflection)不同,Rust使用到了trait机制。

Rust的JSON序列化库

serde提供了通用的序列化功能,诸多具体的数据组织、序列化库的实现都依赖该库,如JSONMessagePack等。基于此库也可以实现自定义的序列化功能,不过很少有人这样做:现有的数据序列化格式众多,选择一个适合的格式往往事半功倍。Rust的JSON库为serde_json,二者配合使用可以实现Rust结构化的自动序列化和反序列化。笔者编写的简单测试例程在Cargo.toml工程配置文件中的依赖为:

serde = { version = "1.0.127", features = ["derive"] }
serde_json = "1.0.66"

笔者指定了二者的具体版本。注意上面的features = ["deriver"]语句,指示在编译serde库时,需要的特性为derive

定义结构体,继承serde提供的序列化特性

serde库提供了对Rust基本数据类型的序列化功能,并通过SerializeDeserailize特性trait向外部提供。只要结构体中的(基本)数据类型都支持这两个特性,那么Rust会通过serde自动组织任一结构体的序列化和反序列化功能。以下是笔者定义的简单结构体:

use std::fs;
use serde_json;
use serde::{Deserialize, Serialize};

#[derive(Debug, Serialize, Deserialize)]
struct CityWeather {
    name:           String,
    temp:           [i32; 2],
    temps:          Vec<i32>,
}

使用serde_json序列化结构体

通过serde_json::to_string(...)函数可以实现任一实现了Serialize特性的结构体的JSON数据的序列化。该接口的详细说明见官方文档,以下是笔者编写的序列化测试代码:

    let beijing = CityWeather {
        name:          "Beijing".to_string(),
        temp:          [23, 31],
        temps:         vec![31, 30, 32, 30, 30],
    };

    let sdata = serde_json::to_string(&beijing);
    if sdata.is_err() {
        println!("Error, failed to serialize structure: {}", sdata.unwrap_err());
        std::process::exit(1);
    }
    let sdata = sdata.unwrap();
    println!("Serialized data:\n{}", sdata);

编译运行的结果如下:

Serialized data:
{"name":"Beijing","temp":[23,31],"temps":[31,30,32,30,30]}

使用serde_json反序列化得到结构体

使用C/C++对JSON字符串反序列化会生成一个链表,或者Json::value之类的对象,而不会生成任意的结构体变量。而Rust可以轻松地实现这一点,反序列化可以生成不同类型的结构体变量。笔者以下JSON数据测试:

{"name":"Shanghai","temp":[24,33],"temps":[33,34,33,32,32,31,35]}

以上数据保存于test.json的文本文件中,反序列化得到CityWeather结构体变量的代码如下:

    let jdata = fs::read_to_string("test.json");
    if jdata.is_err() {
        println!("Error, cannot read 'test.json': {}", jdata.unwrap_err());
        std::process::exit(2);
    }
    let jdata = jdata.unwrap();

    let jvalue = serde_json::from_str(&jdata);
    if jvalue.is_err() {
        println!("Error, invalid json data: {}", jdata);
        std::process::exit(3);
    }
    let jvalue = jvalue.unwrap();
    let weather = serde_json::from_value::<CityWeather>(jvalue);
    if weather.is_err() {
        println!("Error, cannot parse '{}' as CityWeather: {:?}",
            jdata, weather.unwrap_err());
        std::process::exit(4);
    }
    let weather = weather.unwrap();
    println!("Json data from file:\nCity name: {}, temperature: {:?},  prediction: {:?}",
        weather.name, weather.temp, weather.temps);

编译运行结果如下:

Json data from file:
City name: Shanghai, temperature: [24, 33],  prediction: [33, 34, 33, 32, 32, 31, 35]

由此可见,Rust提供的序列化功能库可以很大程度上提升开发效率。

与结构体不匹配的反序列化

注意到,笔者定义的CityWeather中的temp变量,是一个长度为固定2的数组,记录一天当中的最低漫和最高温:

temp: [i32; 2],

它不是一个向量Vec,包含的数据不可增长。如果尝试使用以下数据反序列化,并尝试得到CityWeather结构体变量,上面的代码可以检测到该异常:

{"name":"Shanghai","temp":[24,33,28],"temps":[33,34,33,32,32,31,35]}

temp数组有三个元素,这一数据不能反序列化为CityWeather变量:

Error, cannot parse '{"name":"Shanghai","temp":[24,33,28],"temps":[33,34,33,32,32,31,35]}
' as CityWeather: Error("invalid length 3, expected fewer elements in array", line: 0, column: 0)

由此可见,serde的反序列化功能是很健壮、稳定的。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Rust中,序列序列是将对象转为便于传输的格式和将序列的数据恢复为对象的过程。常见的序列格式包括二进制格式、字节数组、JSON字符串和XML字符串。为了使数据类型支持序列序列,该类型需要实现Serialize和Deserialize trait。在Rust中,可以使用Serde库来提供基础类型和标准库类型的Serialize和Deserialize实现。\[2\]\[3\] 例如,使用Serde库进行JSON序列序列的示例代码如下: ```rust use serde::{Serialize, Deserialize}; use serde_json::{Result, Value}; #\[derive(Serialize, Deserialize)\] struct Person { name: String, age: u32, } fn main() -> Result<()> { // 序列JSON字符串 let person = Person { name: "Alice".to_string(), age: 25, }; let json = serde_json::to_string(&person)?; println!("Serialized JSON: {}", json); // 序列JSON字符串为对象 let deserialized_person: Person = serde_json::from_str(&json)?; println!("Deserialized Person: {:?}", deserialized_person); Ok(()) } ``` 在上面的示例中,我们定义了一个名为Person的结构,并为其实现了Serialize和Deserialize trait。然后,我们可以使用serde_json库的to_string函数将Person对象序列JSON字符串,并使用from_str函数将JSON字符串序列为Person对象。\[1\] 总结起来,Rust中的序列序列是通过实现Serialize和Deserialize trait来将对象转为传输格式和恢复为对象的过程,可以使用Serde库来简序列序列的操作。 #### 引用[.reference_title] - *1* [Rust json 序列序列](https://blog.csdn.net/wsp_1138886114/article/details/109357476)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [Rust 结构数组、序列序列](https://blog.csdn.net/wsp_1138886114/article/details/108835634)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [Rust 中的序列序列](https://blog.csdn.net/u012666784/article/details/112787047)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值