Rust下的JSON动态反序列化

Rust下的结构体反序列化

在之前的一篇文章中,笔者介绍了在Rust编程语言中,使用serde_json包对结构体的序列化和反序列化的基本操作;重点是在定义结构体时,继承源于serde包的 DeserializeSerialize特性:

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

#[derive(Serilize, Deserialize, Debug)]
struct rust_struct {
    member_0: String,
    member_1: String,
    member_2: i32,
}

不过直接将JSON字符串反序列化得到结构体,这一过程对数据源要求是严格的,结构体与JSON数据必须完全对应,数中缺少或增加一个键值对,都会导致反序列化操作失败。而在实际应用中,基于JSON制定的数据协议常常是不断演进、扩展的,若在JSON数据增加或删除某些键值,按照原先的结构体进行反序列化,应用就不能够正常解析。为了避免这个问题,我们需要一种更灵活的、动态的反序列化的处理方式。

serde_json的基础变量:Value

serde_json包提供了用于表示一个基本变量的枚举类型,serde_json::Value,这是一个可递归包含自身的类型,类似于cJSON中的结构体cJSON的定义:

pub enum Value {
    Null,
    Bool(bool),
    Number(Number),
    String(String),
    Array(Vec<Value>),
    Object(Map<String, Value>),
}

这是一个典型的枚举类型的定义。可以看到,对于JSON的对象类型(Object),它用基础库中的表Map对表键值项进行映射。访问或遍历这个表,就可以动态地解析JSON数据。不过需要注意的是,这种解析方法,会解析JSON字符串的所有项:对于一个很长的JSON字符串,尽管我们只需要其中的小部分数据项,但仍需要完整的解析,这会浪费一定的计算资源。值得一提的是,serde_json有只对部分数据进行解析的功能,可进一步提升数据解析的效率,这里不作探讨。

JSON的动态解析

为方便参考,笔者编写了简单的JSON数据的动态解析,代码全部内容如下(编译得到dyn-json执行文件):

/* dyn-json.rs */
use serde_json::Value;

fn dump_json_value(jval: &Value, level: usize) -> i32 {
	let jobjs = jval.as_object();
	if jobjs.is_none() {
		return 0;
	}
	let jobjs = jobjs.unwrap();
	let name = jobjs.get("name");
	if name.is_some() {
		println!("JSON object has name field: {}", name.unwrap());
	} else {
		println!("JSON object has no name filed.");
	}
	let lstr = if level > 0 { "\t".repeat(level) } else { "".to_string() };
	for jkey in jobjs.keys() {
		let obj = jobjs.get(jkey).unwrap();
		if obj.is_array() {
			println!("{}{} => ARRAY", lstr, jkey);
		} else if obj.is_boolean() {
			println!("{}{} => {}", lstr, jkey, obj.as_bool().unwrap());
		} else if obj.is_f64() {
			println!("{}{} => {}", lstr, jkey, obj.as_f64().unwrap());
		} else if obj.is_i64() {
			println!("{}{} => {}", lstr, jkey, obj.as_i64().unwrap());
		} else if obj.is_null() {
			println!("{}{} => NULL", lstr, jkey);
		} else if obj.is_u64() {
			println!("{}{} => {}", lstr, jkey, obj.as_u64().unwrap());
		} else if obj.is_object() {
            println!("{}{} =>", lstr, jkey);
			dump_json_value(obj, level + 1);
		} else if obj.is_string() {
			println!("{}{} => {}", lstr, jkey, obj.as_str().unwrap());
		} else {
			println!("{}{} => UNKNOWN TYPE", lstr, jkey);
		}
	}
	return 0;
}

fn main() {
	let filename = std::env::args().nth(1).unwrap_or("./sample.json".to_string());
	let filedata = std::fs::read_to_string(&filename);
	if filedata.is_err() {
		eprintln!("{}: {:?}", filename, filedata.err());
		std::process::exit(1);
	}
	let filedata = filedata.unwrap();
	let jsondata= serde_json::from_str::<Value>(&filedata);
	if jsondata.is_err() {
		eprintln!("Error, failed to parse jsondata: {}", filedata);
		std::process::exit(1);
	}
	let jsondata = jsondata.unwrap();
	dump_json_value(&jsondata, 0);
}

笔者使用以下数据源sample.json进行测试:

{
    "name": "John Doe",
    "age": 43,
    "address": {
        "street": "10 Downing Street",
        "city": "London"
    },
    "phones": [
        "+44 1234567",
        "+44 2345678"
    ],
	"testnull": null,
	"testint": -1,
	"the": 2021,
	"rust": 1.60,
	"programming": 68719476736,
	"language": true
}

测结果如下:

# ./target/release/dyn-json ./samples.json
JSON object has name field: "John Doe"
address =>
JSON object has no name filed.
	city => London
	street => 10 Downing Street
age => 43
language => true
name => John Doe
phones => ARRAY
programming => 68719476736
rust => 1.6
testint => -1
testnull => NULL
the => 2021

可见,Rust下的JSON数据动态解析流程与cJSON的解析流程很接近:这样的数据解析方式是灵活的,能够避免因数据格式变化造成Rust结构体反序列化失败的问题。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 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、付费专栏及课程。

余额充值