JSON5 (serde) 中的变体类型 [duplicate]

Variant types in JSON5 (serde) [duplicate]

提问人:PasterOfMuppets 提问时间:11/8/2023 最后编辑:cafce25PasterOfMuppets 更新时间:11/8/2023 访问量:66

问:

我想知道当通过 serde 映射时,如何在 JSON 中支持“type-fluid”(又名变体类型)字段。作为解析器,我正在使用 crate(由 支持)。某些输入字段可能包含键值,这些键值是同一键后面的键值或列表,即 .json5serde"foo": "bar""foo": [ "bar", "and", "more" ]

https://serde.rs/data-model.html 的文档实际上并没有给我提供有关如何映射此用例的线索。我尝试使用枚举作为变体载体,见下文,但这不起作用,在运行时,这最终会导致一些错误结果,例如.Err(Message { msg: "unknown variant `hello world`, expected `Single` or `Multi`", location: Some(Location { line: 4, column: 20 }) })

到目前为止,我仍然没有看到一种方法可以告诉它“将其作为值或值列表,让我看看您解析了哪种类型”。

#[derive(Deserialize, Debug, PartialEq)]
enum StringOrStrings {
    Single(String),
    Multi(Vec<String>),
}

#[derive(Deserialize, Debug, PartialEq)]
struct Config {
    message: StringOrStrings,
    n: i32,
}
rust serde json5

评论

2赞 BallpointBen 11/8/2023
您可以在这里找到所有答案: serde.rs/enum-representations.html

答:

2赞 Urban48 11/8/2023 #1

给你:
这里基本一样的答案

游乐场链接

extern crate serde;
extern crate serde_json;

use serde::{Deserialize, Serialize};
use serde_json::Value;


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

#[derive(Deserialize, Debug)]
struct Config {
    message: StringOrStringVec,
    n: i32,
}

fn main (){
    let json_string = r#"
        {
            "message": "hello",
            "n": 42
        }
    "#;

    let json_vec = r#"
        {
            "message": ["hello", "world"],
            "n": 42
        }
    "#;

    let my_obj: Config = serde_json::from_str(json_string).unwrap();
    println!("{:?}", my_obj);
    
    let my_obj: Config = serde_json::from_str(json_vec).unwrap();
    println!("{:?}", my_obj);
}

评论

0赞 cdhowie 11/8/2023
在这种情况下,不需要注意。extern crate
1赞 PasterOfMuppets 11/8/2023
谢谢。两者都是很好的答案,但@cdhowie的答案已经领先了一步,使我免于以后繁琐的类型推论。
1赞 cdhowie 11/8/2023 #2

正如另一个答案所解释的那样,您可以使用未标记的枚举,它允许您从几个选项中反序列化一个,按顺序尝试每个选项,直到一个成功。

但是,您可以进一步推广此解决方案以处理任何可反序列化的数据类型(而不仅仅是字符串),以及通过将单个值包装在如下所示中来隐藏“可能”详细信息:VecVec

use serde::{Deserialize, Deserializer};

#[derive(Deserialize, Debug)]
struct Config {
    #[serde(deserialize_with = "deser_maybe_vec")]
    message: Vec<String>,
    n: i32,
}

fn deser_maybe_vec<'de, D, T>(deserializer: D) -> Result<Vec<T>, D::Error>
where
    D: Deserializer<'de>,
    T: Deserialize<'de>,
{
    #[derive(Deserialize)]
    #[serde(untagged)]
    enum SingleOrVec<T> {
        Single(T),
        Vec(Vec<T>),
    }

    Ok(match SingleOrVec::deserialize(deserializer)? {
        SingleOrVec::Single(v) => vec![v],
        SingleOrVec::Vec(v) => v,
    })
}

请注意,如果需要派生,则无需专门处理这种情况,因为默认实现将生成一个包含一个项目的序列,该序列是数据的有效表示形式。SerializeConfigserialize_with