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

Rust 使用Serde反序列化时,如何将特殊值转换为Option::None?,rust,serde,Rust,Serde,我正在将数据解析为: struct Data { field1: Option<f32>, field2: Option<u64>, // more ... } struct数据{ 字段1:选项, 字段2:选项, //更多。。。 } 问题是我的输入数据格式将Rust中的None格式设置为“n/a” 如何告诉Serde,对于特定字符串n/a,选项应该是None,而不是错误?我们可以假设这不适用于字符串 这与问题不同,因为这是从一个特殊值创建一个f

我正在将数据解析为:

struct Data {
    field1: Option<f32>,
    field2: Option<u64>,
    // more ...
}
struct数据{
字段1:选项,
字段2:选项,
//更多。。。
}
问题是我的输入数据格式将Rust中的
None
格式设置为“
n/a

如何告诉Serde,对于特定字符串
n/a
,选项
应该是
None
,而不是错误?我们可以假设这不适用于
字符串


这与问题不同,因为这是从一个特殊值创建一个
f32
,而我的问题是创建一个
选项,因为它仍然涉及一个特定类型。

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

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"))
            }
        }
    }
}

有关更多信息,请参阅文档:


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

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"))
            }
        }
    }
}

有关更多信息,请参阅文档:


很难回答您的问题,因为它没有包含一个。我们无法确切地说出您的输入是什么样子的,或者即使它是JSON、YAML还是。。。。如果您试图重现您的错误(如果可能的话),或者在全新的货运项目中,那么我们将更容易帮助您,然后您的问题将包括附加信息。您可以使用以下方法减少在此处发布的原始代码。谢谢很难回答你的问题,因为它不包括一个。我们无法确切地说出您的输入是什么样子的,或者即使它是JSON、YAML还是。。。。如果您试图重现您的错误(如果可能的话),或者在全新的货运项目中,那么我们将更容易帮助您,然后您的问题将包括附加信息。您可以使用以下方法减少在此处发布的原始代码。谢谢这可能的重复不仅回答了我的问题,而且说明了如何在serde的现有反序列化器上生成一个广义包装器。@njaard正是这么说的。这不仅回答了我的问题,还说明了如何在serde的现有反序列化器上生成一个广义包装器。@njaard正是这么说的