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

https://serde.rs/data-model.html的文档实际上并没有给我一个关于如何映射这个用例的线索.我try 使用枚举作为变量载体,见下文,但这不起作用,在运行时,这最终导致一些错误结果,如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,
}

推荐答案

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

但是,您可以进一步推广此解决方案,以处理any个可反序列化的数据类型(不仅仅是字符串),并通过将单个值包装在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,
    })
}

请注意,如果需要在Config上派生Serialize,则不需要特别使用serialize_with来处理这种情况,因为默认实现将生成一个包含一项的序列,这是数据的有效表示形式.

Rust相关问答推荐

if let声明中临时对象的生存期

如何对字符串引用的引用向量进行排序,而不是对最外层的引用进行排序?

`Pin`有没有不涉及不安全代码的目的?

为什么rustc会自动降级其版本?

了解Rust';s特征对象和不同函数签名中的生存期注释

什么是`&;[][..]`铁 rust 里的刻薄?

通过异常从同步代码中产生yield 是如何工作的?

Windows 上 ndarray-linalg 与 mkl-stats 的链接时间错误

如何重命名 clap_derive 中的子命令占位符?

随机函数不返回随机值

Nom 解析器无法消耗无效输入

我们可以在 Rust 切片中使用步骤吗?

为什么Rust编译器会忽略模板参数应具有静态生命周期?

`tokio::pin` 如何改变变量的类型?

Rust 将特性传递给依赖项

If let expression within .iter().any

如何异步记忆选项中的 struct 字段

为什么这个闭包没有比 var 长寿?

在使用大型表达式时(8k 行需要一小时编译),是否可以避免 Rust 中的二次编译时间?

在 Rust 中有条件地导入?