JSON可能是最常用的数据结构,可以将它用于配置、数据库等。
json数据结构的最佳实践是为每个属性提供一个静态key,但有时我们需要处理动态key。
serde_json
在rust中,我们使用的是serde_json库,它有很好用的api。让我们看看如何用serde_json解析json。
让我们将serde依赖添加到Cargo.toml中。我们将使用serde将数据序列化为struct:
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
现在让我们解析一些带有静态key属性的json:
use serde::{Deserialize, Serialize};
use serde_json::Result;
#[derive(Serialize, Deserialize)]
struct User {
username: String,
age: usize,
email: String,
full_name: Vec<String>,
}
pub fn main() -> Result<()> {
let data = r#"
{
"username": "ahmadrosid",
"email": "alahmadrosid@gmail.com",
"age": 27,
"full_name": [
"Ahmad",
"Rosid"
]
}"#;
let u: User = serde_json::from_str(data)?;
println!("Hi {}", u.full_name[0]);
Ok(())
}
使用静态key属性,我们可以很容易地向结构声明键和类型。但如果key是动态的,我们就无法这么处理。
动态Json
幸运的是,serde_json有个枚举Value来处理json的数据结构:
enum Value {
Null,
Bool(bool),
Number(Number),
String(String),
Array(Vec<Value>),
Object(Map<String, Value>),
}
有了这个enum,我们可以检查每个key并对其进行一些序列化。现在,假设我们有这个json:
{
"plugins": {
"width": [["w",["width"]]],
"height": [["h",["height"]]],
"z_index": [["z",["z-index"]]]
}
}
这看起来很简单,对吧?我们可以像这样轻松地定义struct:
#[derive(Serialize, Deserialize)]
struct Data {
plugins: Plugin,
}
#[derive(Serialize, Deserialize)]
struct Plugin {
width: Vec<Value>,
height: Vec<Value>,
z_index: Vec<Value>,
}
但是,如果plugins内部的key是动态的,例如,如果z_index变成了z-index,并且多于三个key,该怎么办呢?
为了处理这种情况,我们需要把这个数据转换为Map<String, Value>。现在我们可以将struct写成这样:
#[derive(Serialize, Deserialize)]
struct Data {
plugins: Map<String, Value>,
}
现在我们可以像这样访问数据:
let data: Data = serde_json::from_str(json)?;
let z_index: Value = data.get("z_index").unwrap();
要将Value转换为数组,我们可以这样做:
let z_index_arr: Vec<&Value> = z_index.as_array().unwrap();
我们还可以通过将数组z_index中的值转换为键值来改进。正如你所看到的,z_index的值是数组中的数组:
[
[
"z",
[
"z-index"
]
]
]
让我们把这个值转换为:
{
"z": ["z-index"]
}
为此,我们将直接使用Map<String, Value>:
let z_index_arr = z_index.as_array().unwrap();
let mut data = Map::new();
for item in z_index_arr {
if item.get(0).unwrap().is_string() {
let key = item.get(0).unwrap().as_str().unwrap().to_string();
let variants = item.get(1).unwrap().clone();
data.insert(key, variants);
}
}
现在我们可以这样访问z-index的值:
let arr = data.get("z").unwrap();
println!("{}", arr);
完整代码如下:
use serde::{Serialize, Deserialize};
use serde_json::{Result, Map, Value};
#[derive(Serialize, Deserialize)]
struct Data {
plugins: Map<String, Value>
}
fn main() -> Result<()> {
let json = r#"
{
"plugins": {
"width": [["w",["width"]]],
"height": [["h",["height"]]],
"z_index": [["z",["z-index"]]]
}
}
"#;
let data: Data = serde_json::from_str(json)?;
let z_index = data.plugins.get("z_index").unwrap();
let z_index_arr = z_index.as_array().unwrap();
let mut data = Map::new();
for item in z_index_arr {
if item.get(0).unwrap().is_string() {
let key = item.get(0).unwrap().as_str().unwrap().to_string();
let variants = item.get(1).unwrap().clone();
data.insert(key, variants);
}
}
let arr = data.get("z").unwrap();
println!("{}", arr);
Ok(())
}
就这些了,可以查看serde的文档了解更多使用方法。
本文翻译自:
https://www.ahmadrosid.com/blog/rust-parsing-dynamic-json