【问题标题】:Serialize JSON in a recursive struct在递归结构中序列化 JSON
【发布时间】:2016-02-26 23:29:27
【问题描述】:

我有这个 JSON:

{
  "argument0": {
    "argument1": "test",
    "argument2": {
       "argument3": "test3"
    }          
  }
}

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

#[derive(Clone, RustcDecodable, RustcEncodable)]
struct Argument {
    key: String
    value: String Or Argument
}

我怎样才能做到这一点?

【问题讨论】:

  • 欢迎来到 Stack Overflow!在提出问题时,我们希望您向我们展示the research you have done。这有助于了解您缺少什么并提供答案。它还有助于淘汰那些想要将 SO 用作代码编写服务的人(事实并非如此)。你应该edit你的问题包括你尝试了什么,为什么这不起作用,然后我们可以从那里开始。
  • 你的 struct 对应一个单链表,而你的 json 对象似乎是一棵树,所以有问题。我最好的建议是在开始担心 json 之前先创建正确的数据结构。此外,在导入之前尝试导出为 json。这是导出到 doc.rust-lang.org/num/rustc_serialize/json/index.html 的手册页您可能应该阅读 om 枚举以便能够表示 StringOrArgument doc.rust-lang.org/book/enums.html
  • 感谢 Shepmaster,Niesle 的 cmets。 Niesle,我在这里研究了树的表示:stackoverflow.com/questions/21791786/…,感谢这个方向,现在我可以重做一些编码来按照你的建议查看导出的 json。 json 中的表示很重要,因为这是针对 REST API 的,我需要这种精确的表示。

标签: json recursion struct hashmap rust


【解决方案1】:

这里有一些明显的问题。

首先,您希望能够定义一种数据类型,它可以是一种类型,也可以是另一种类型,但不能同时是两种类型。这就是 Rust 的 enum data type 的用途。

enum Value {
    String(String),
    Argument(Argument),
}

Value 类型可以包含StringArgument,但不能同时包含两者。

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

use std::collections::BTreeMap;

type Argument = BTreeMap<String, Argument>;

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

对于大多数结构,我们只需添加一个#[derive(Serialize)] 和/或#[derive(Deserialize)] 来实现序列化所需的特征。在这种情况下,我们希望将 enum 的反序列化自定义为 untagged,因此它只发出枚举的值,而不是以“String”或“Argument”为键的对象。相反,我们只希望 JSON 包含该值。为此,我们向结构体添加了一个特殊属性#[serde(untagged)]

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

#[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);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-01-24
    • 1970-01-01
    • 2022-01-07
    • 1970-01-01
    • 1970-01-01
    • 2016-10-27
    • 2014-01-11
    • 2016-09-05
    相关资源
    最近更新 更多