栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Rust下的JSON动态反序列化

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Rust下的JSON动态反序列化

Rust下的结构体反序列化

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

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),
    Object(Map),
}

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

JSON的动态解析

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

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::(&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结构体反序列化失败的问题。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/927334.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号