在递归结构中序列化 JSON

qio*_*qio 5 recursion json struct hashmap rust

我有这个 JSON:

{
  "argument0": {
    "argument1": "test",
    "argument2": {
       "argument3": "test3"
    }          
  }
}
Run Code Online (Sandbox Code Playgroud)

我需要使用某种递归结构和HashMap<String, _>Rust 之类的方法。键应始终是 aString但值可以是 aString或相同的Argument结构。

#[derive(Clone, RustcDecodable, RustcEncodable)]
struct Argument {
    key: String
    value: String Or Argument
}
Run Code Online (Sandbox Code Playgroud)

我怎样才能做到这一点?

euc*_*lio 5

你在这里有一些明显的问题。

首先,您希望能够定义一种数据类型,该数据类型可以是一种类型或另一种类型,但不能同时是两种类型。这就是 Rustenum数据类型的用途。

enum Value {
    String(String),
    Argument(Argument),
}
Run Code Online (Sandbox Code Playgroud)

Value类型可以包含 aString或 an Argument,但不能同时包含两者。

现在,我们需要定义Argument类型。在您的示例中,参数可以包含任意字段名称,因此我们不能只定义struct. 相反,我们可以使用标准库中的映射集合StringValues映射到s,例如BTreeMap. 我们还将定义一个类型别名,以便我们可以使用该名称Argument而不是BTreeMap<String, Argument>程序中的其他地方。

use std::collections::BTreeMap;

type Argument = BTreeMap<String, Argument>;
Run Code Online (Sandbox Code Playgroud)

现在我们已经成功定义了类型,让我们使用serde库定义它的序列化行为。Serde 可以自动序列化来自 Rust 标准库的类型,用户结构可以实现或派生SerializeDeserializetrait 以将功能添加到他们自己的类型中。

对于大多数结构,我们只需添加一个#[derive(Serialize)]和/或#[derive(Deserialize)]来实现序列化所需的特征。在这种情况下,我们要自定义我们的反序列化enum未标记的,所以它只是发出枚举的价值,而不是用“字符串”或“论证”作为重点对象。相反,我们只希望 JSON 包含该值。我们通过向结构体添加一个特殊属性来做到这一点,#[serde(untagged)].

这是一个简短的 Rust 程序,演示了上述概念。该程序将读取您的 JSON 示例,并打印Debug表示数据的 Rust 类型的表示。

#[macro_use]
extern crate serde_derive; // 1.0.78
extern crate serde; // 1.0.78
extern crate serde_json; // 1.0.27

use std::collections::BTreeMap;


#[derive(Debug, Serialize, Deserialize)]
#[serde(untagged)]
enum Value {
    String(String),
    Argument(Argument),
}

type Argument = BTreeMap<String, Value>;

fn main() {
    let argument: Argument = serde_json::from_str(
        r#"{
            "argument0": {
                "argument1": "test",
                "argument2": {
                    "argument3": "test3"
                }          
            }
        }"#,
    ).unwrap();

    println!("{:?}", argument);
}
Run Code Online (Sandbox Code Playgroud)