使用Serde反序列化时如何将特殊值转换为Option::None?

nja*_*ard 4 rust serde

我将数据解析为:

struct Data {
    field1: Option<f32>,
    field2: Option<u64>,
    // more ...
}
Run Code Online (Sandbox Code Playgroud)

问题是我的输入数据格式将NoneRust 中的 a 格式化为“ n/a”。

如何告诉 Serde anOption<T>应该代表None特定的 string n/a,而不是错误?我们可以假设这不适用于String.

这与How to deserialize "NaN" as `nan` with serde_json?不是同一个问题。因为这是从一个特殊值创建一个f32,而我的问题是从一个特殊值创建一个Option<Anything>。这也不是如何使用 Serde 反序列化期间转换字段?因为这仍然涉及特定类型。

Frx*_*rem 7

您可以编写自己的反序列化函数来处理这种情况:

use serde::de::Deserializer;
use serde::Deserialize;

// custom deserializer function
fn deserialize_maybe_nan<'de, D, T: Deserialize<'de>>(
    deserializer: D,
) -> Result<Option<T>, D::Error>
where
    D: Deserializer<'de>,
{
    // we define a local enum type inside of the function
    // because it is untagged, serde will deserialize as the first variant
    // that it can
    #[derive(Deserialize)]
    #[serde(untagged)]
    enum MaybeNA<U> {
        // if it can be parsed as Option<T>, it will be
        Value(Option<U>),
        // otherwise try parsing as a string
        NAString(String),
    }

    // deserialize into local enum
    let value: MaybeNA<T> = Deserialize::deserialize(deserializer)?;
    match value {
        // if parsed as T or None, return that
        MaybeNA::Value(value) => Ok(value),

        // otherwise, if value is string an "n/a", return None
        // (and fail if it is any other string)
        MaybeNA::NAString(string) => {
            if string == "n/a" {
                Ok(None)
            } else {
                Err(serde::de::Error::custom("Unexpected string"))
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

然后您可以标记您的字段以#[serde(default, deserialize_with = "deserialize_maybe_nan")]使用此函数而不是默认函数:

#[derive(Deserialize)]
struct Data {
    #[serde(default, deserialize_with = "deserialize_maybe_nan")]
    field1: Option<f32>,
    #[serde(default, deserialize_with = "deserialize_maybe_nan")]
    field2: Option<u64>,
    // more ...
}
Run Code Online (Sandbox Code Playgroud)

工作游乐场示例

文档中的更多信息: