提问人:PasterOfMuppets 提问时间:11/8/2023 最后编辑:cafce25PasterOfMuppets 更新时间:11/8/2023 访问量:66
JSON5 (serde) 中的变体类型 [duplicate]
Variant types in JSON5 (serde) [duplicate]
问:
我想知道当通过 serde 映射时,如何在 JSON 中支持“type-fluid”(又名变体类型)字段。作为解析器,我正在使用 crate(由 支持)。某些输入字段可能包含键值,这些键值是同一键后面的键值或列表,即 .json5
serde
"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,
}
答:
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
正如另一个答案所解释的那样,您可以使用未标记的枚举,它允许您从几个选项中反序列化一个,按顺序尝试每个选项,直到一个成功。
但是,您可以进一步推广此解决方案以处理任何可反序列化的数据类型(而不仅仅是字符串),以及通过将单个值包装在如下所示中来隐藏“可能”详细信息:Vec
Vec
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,
})
}
请注意,如果需要派生,则无需专门处理这种情况,因为默认实现将生成一个包含一个项目的序列,该序列是数据的有效表示形式。Serialize
Config
serialize_with
评论