JSON 可能是最常用的数据结构。您可以将其用于配置、数据库等。
json 数据结构的最佳实践都是针对每个属性都有静态键的情况,但但有时我们需要处理动态键。
serde_json
在 rust 中,我们使用的是 serde_json 库,它有很好的 api 可以使用。那么我们来看看如何用serde_json解析json。
让我们将 serde 依赖添加到Cargo.toml。我们将使用serde将我们的数据序列化为 struct。
serde = { version = "1.0", features = ["derive"] } serde_json = "1.0"
|
现在让我们解析一些带有静态键属性的 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(()) }
|
使用静态键属性,我们可以轻松地向结构声明键和类型。但是,如果密钥是动态的,我们将无法处理。
动态Json
幸运的是 serde_json 有这个枚举来处理 json 数据结构:
enum Value { Null, Bool(bool), Number(Number), String(String), Array(Vec<Value>), Object(Map<String, Value>), }
|
使用这个枚举,我们可以检查每个键并对其进行一些序列化。现在,假设我们有这个 json:
{ "plugins": { "width": [["w",["width"]]], "height": [["h",["height"]]], "z_index": [["z",["z-index"]]], } }
|
看起来很简单吧?我们可以像这样轻松地声明结构。
#[derive(Serialize, Deserialize)] struct Data { plugins: Plugin, }
#[derive(Serialize, Deserialize)] struct Plugin { width: Vec<Value>, height: Vec<Value>, z_index: Vec<Value>, }
|
但是,如果插件中的键是动态的,例如,如果z_index变成了z-index,而且键的数量超过了例子中的三个,怎么办?
#[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" ] ] ]
|
让我们把这个值变成:
为了做到这一点,我们将直接使用Map<String, Value>:
let z_index: Vec<&Value> = data.get("z-index").unwrap().as_array().unwrap(); let mut data = Map::new();
for item in z_index { if item.get(0)?.is_string() { let key = item.get(0)?.as_str()?.to_string(); let variants = item.get(1)?.clone(); } } 小提示! 如果你不想每次转换枚举值时都使用unwrap(),只需使用? 并用Option<()>来包装你的函数
|
现在我们可以这样访问z-index的值:
let arr: Vec<&Value> = data.get("z")?;
|
serde 的更多文档。