rust 使用Serde反序列化具有多种类型字段的JSON

vd2z7a6w  于 2022-12-04  发布在  其他
关注(0)|答案(1)|浏览(162)

我有一些JSON文本数据,其中的字段可以是字符串或字符串数组。

{
        "keya": "some string",
        "keyb": "some string"
}

{
        "keya": "some string",
        "keyb": ["some string", "some string"]
}

{
        "keya": ["some string", "some string"],
        "keyb": "some string"
}

{
        "keya": ["some string", "some string"],
        "keyb": ["some string", "some string"]
}

如何创建一个类型,使我可以使用Serde反序列化这样的JSON文本数据?

yacmzcpb

yacmzcpb1#

该答案早于OP作为注解给出的额外要求,但由于额外要求使其成为一个单独的问题而保留。

若要行程结尾逗号

问题中提供的输入数据不是有效的JSON,因为每个右括号}前面都有尾随逗号。如果您 * 必须 * 使用尾随逗号,那么传统的serde_json crate就不适合您的需要,并且您可能希望将serde_json的所有用法替换为支持尾随逗号的板条箱(如the json5 crate)。json5提供了一个API,该API“s类似于serde_json,因此下面的答案仍然有效。

处理可以是多种类型的字段

处理具有多种可能值类型的JSON字段可以使用enum来完成,该enum包含StringVec<String>以及#[serde(untagged)]属性。有关该属性的详细信息,请参阅serde官方文档中的Enum representations
完整示例:

use serde::{Serialize, Deserialize};

#[derive(Debug, Serialize, Deserialize)]
#[serde(untagged)]
enum StringOrStringVec {
    String(String),
    Vec(Vec<String>)
}

#[derive(Debug, Serialize, Deserialize)]
struct MyObj {
    keya: StringOrStringVec,
    keyb: StringOrStringVec,
}

fn main() {
    let input_json = r#"
        {
            "keya": "some string",
            "keyb": ["some string", "some string"]
        }
    "#;
    let my_obj: MyObj = serde_json::from_str(input_json).unwrap();
    println!("{:?}", my_obj);
    
    let input_json = r#"
        {
            "keya": ["some string", "some string"],
            "keyb": "some string"
        }
    "#;
    let my_obj: MyObj = serde_json::from_str(input_json).unwrap();
    println!("{:?}", my_obj);
}

输出示例:

MyObj { keya: String("some string"), keyb: Vec(["some string", "some string"]) }
MyObj { keya: Vec(["some string", "some string"]), keyb: String("some string") }

See it in action on Rust Playground

相关问题