Я разбираю данные в:
struct Data {
field1: Option<f32>,
field2: Option<u64>,
// more ...
}
Проблема в том, что мой формат входных данных форматирует то, что было бы None
в Rust, как «n/a
».
Как сказать Серде, что Option<T>
должен быть None
для конкретной строки n/a
, а не ошибкой? Можно предположить, что это не относится к String
.
Это не тот же вопрос, что и Как десериализовать «NaN» как «nan» с помощью serde_json?, потому что он создает f32
из специального значения, тогда как мой вопрос создает Option<Anything>
из специального значения. Это также не Как преобразовать поля при десериализации с помощью Serde?, так как это все еще относится к определенному типу.
Возможный дубликат Как преобразовать поля при десериализации с помощью Serde?
Вы можете написать свою собственную функцию десериализации, которая обрабатывает этот случай:
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"))
}
}
}
}
Затем вы можете пометить свои поля #[serde(default, deserialize_with = "deserialize_maybe_nan")]
, чтобы использовать эту функцию вместо функции по умолчанию:
#[serde(Deserialize)]
struct Data {
#[serde(default, deserialize_with = "deserialize_maybe_nan")]
field1: Option<f32>,
#[serde(default, deserialize_with = "deserialize_maybe_nan")]
field2: Option<u64>,
// more ...
}
Больше информации в документации:
deserialize_with
атрибут сердеЭто не только отвечает на мой вопрос, но и показывает, как создать обобщенную оболочку для существующих десериализаторов serde.
@njaard это именно то, что говорит stackoverflow.com/questions/46753955/…
Трудно ответить на ваш вопрос, потому что он не включает минимальный воспроизводимый пример. Мы не можем сообщить точно, как выглядит ваш ввод, или даже если это JSON, YAML или .... Нам будет проще помочь вам, если вы попытаетесь воспроизвести свою ошибку в Детская площадка ржавчины, если это возможно, в противном случае в совершенно новый проект Cargo, затем редактировать ваш вопрос, чтобы включить дополнительную информацию. Есть Советы по MCVE для Rust, которые вы можете использовать, чтобы уменьшить исходный код для публикации здесь. Спасибо!