繁体   English   中英

在递归结构中序列化JSON

[英]Serialize JSON in a recursive struct

我有这个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
}

我怎样才能做到这一点?

你在这里有一些不同的问题。

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

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

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

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

use std::collections::BTreeMap;

type Argument = BTreeMap<String, Argument>;

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

对于大多数结构,我们可以添加#[derive(Serialize)]和/或#[derive(Deserialize)]来实现序列化的必要特征。 在这种情况下,我们想要将我们的enum的反序列化自定义为未标记 ,因此它只发出枚举的值,而不是以“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);
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM