一个JSON的序列化问题

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

Rust的JSON序列化库

serde 提供了通用的序列化功能,诸多具体的数据组织、序列化库的实现都依赖该库,如 JSON MessagePack 等。基于此库也可以实现自定义的序列化功能,不过很少有人这样做:现有的数据序列化格式众多,选择一个适合的格式往往事半功倍。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的反序列化功能是很健壮、稳定的。

一个JSON的序列化问题与人聊天时偶然问到一个问题:“给定任意一个(C/C++)结构体,如何实现其JSON的序列化和反序列化,而不用专门编写相应的序列化、反序列化实现代码?”我摇摇头,表示不知如何实现这一功能;现在我也认为,这一功能对于C/C++,是不可能自动化实现的。不过对于其他的静态编译型编程语言,如Golang/Rust等,这一功能则相对容易实现。与Golang的反射机制(Reflection)不同,Rust使用到了trait机制。Rust的JSON序列化库serde提供了通用的序列化功能,诸多
哈尔斯HTTP 存档格式 (HAR)序列化反序列化库,用 Rust 编写。安装将以下内容添加到Cargo.toml文件中:[dependencies ]har =" 0.6"用externcrate har;fnmain () {match har::from_path ("path/to/file.har" ) {Ok (spec)=>println! ("spec: {:?}" , spec),Err (err)=>println! ("error: {}" , err) }贡献该项目遵循semver 、常规提交和使用mandrean/semantic-rs 的语义发布。笔记灵感来自softprops/openapi 。
文章目录一、json-rust1.1 反序列化1.2 序列化 Serialize二、Serde JSON三、拓展:【使用 Rust 写 Parser 】 json在大多数的语言中都具有举足轻重的地位,特别在网络传中的常用数据交换格式。【百度百科】 关于 Rust 结构数组、序列化反序列化 。 一、json-rust 下面会举例一些常用的json序列化反序列化的用法,在Rustjson对象详情【请查看】 1.1 反序列化 反序列化 json::parse json-rust:https://github
序列化: 将数据结构或对象转换成二进制序列的过程。 反序列化:将在序列化过程中所生成的二进制序列转换成数据结构或者对象的过程。 Serde 是对 Rust 数据结构进行序列化反序列化一种常用框架。 Serde 中的 trait Serde 定义了 4 种 trait: Deserialize A data structure that can be deserialized from any data format supported by Serde. Deserializer A data form
脏数据问题 serde::Value 带来的脏数据问题,使得导入二维数组或者数字类型数据会无法处理 let f = File::open("./test.json").unwrap(); let v
Rust下的结构体反序列化 在之前的一篇文章中,笔者介绍了在Rust编程语言中,使用serde_json包对结构体序列化反序列化的基本操作;重点是在定义结构体时,继承源于serde包的 Deserialize及Serialize特性: use serde_json; use serde::{Deserialize, Serialize}; #[derive(Serilize, Deserialize, Debug)] struct rust_struct { member_0: String,
serde 提供了常见序列化格式串的支持。下面给出一个 json 串转换的例子。 1. 编辑 Cargo.toml 首先编辑 Cargo.toml 文件,引入 serde 软件包。 [dependencies] serde = { version = "1.0.117", features = ["derive"] } serde_json = "1.0.59" 2. 测试程序 接下来看个例子: use serde::{Serialize, Deserialize}; #[derive(Serializ
翻译: kula serde, 是rust语言用来序列化反序列化数据的一个非常高效的解决方案。 本质上,serde提供了一个序列化层的概念。可以将任何支持的数据格式反序列化成中间格式,然后序列化成任何一种支持的数据格式。 同其他语言通过反射来实现序列化方案不同,serde基于rust的trait系统来实现自己的序列化,每种数据
#[stable(feature = "rust1", since = "1.0.0")] pub struct Arc<T: ?Sized> { ptr: Shared<ArcInner<T>>, #[stable(feature = "rust1", since = "1.0.0")] unsafe impl<T: ?Sized + Sync + Send> Send for Arc<T> {}//实现Send Trait
一旦定义了结构体后,为了使用它,通过为每个字段指定具体值来创建这个结构体的 实例。创建一个实例需要以结构体的名字开头,接着在大括号中使用 key: value 键-值对的形式提供字段,其中 key 是字段的名字,value 是需要存储在字段中的数据值。实例中字段的顺序不需要和它们在结构体中声明的顺序一致。换句话说,结构体的定义就像一个类型的通用模板,而实例则会在这个模板中放入特定数据来创建这个类型的值。 声明一个特定的用户: 为了从结构体中获取某个特定的值,可以使用点号。举个例子,想要用户的邮箱地址,可以用
Rust 中,Option<T> 是一个枚举类型,用于表示一个值是否存在。它有两个可能的值:Some(T) 和 None。 你可以使用如下语法来初始化一个 Option<T> 类型: let x: Option<i32> = Some(5); let y: Option<i32> = None; 在上面的代码中,`x` 被初始化为 Some(5),表示存在一个 i32 类型的值 5。`y` 被初始化为 None,表示不存在值。 你还可以使用如下方式来初始化 Option<T> 类型: let x = Some(5); let y = None; 在这种情况下,编译器会自动推断出 x 和 y 的类型为 Option<i32>。