【问题标题】:Deserialize inner enum value from &str to u64 with serde_json使用 serde_json 将内部枚举值从 &str 反序列化为 u64
【发布时间】:2020-01-22 10:35:06
【问题描述】:

我希望能够在 json 对象中将颜色写为十六进制,然后将其反序列化为我的枚举 Coloru64 类型的内部值。

目前我有一个像这样的枚举:

#[derive(Deserialize, Serialize)]
pub enum Color {
   Red,
   Green,
   Blue,
   Custom(u64)
}

然后我在一个看起来像这样的结构中使用它:

pub struct Config {
    #[serde(rename = "borderColor", deserialize_with = "color_deserialize")]
    pub border_color: Color,
}

自定义反序列化函数:

fn color_deserialize<'de, D>(desierializer: D) -> Result<Color, D::Error> 
where
    D: Deserializer<'de>
{
    use serde::de::Error;
    let col = match Color::deserialize(desierializer) {
        Ok(col) => col,
        Err(e) => return Err(format!("Failed to deserilize color: {}", e)).map_err(Error::custom)
    };

    match col {
        Color::Custom(x) => {
            let x_str = &x.to_string();
            let without_prefix = x_str.trim_start_matches("#");
            let res = match u64::from_str_radix(without_prefix, 16) {
                Ok(res) => res,
                Err(e) => return Err(format!("Failed to deserialize color: {}", e)).map_err(Error::custom)
            };
            Ok(Color::Custom(res))
        },
        x => Ok(col)
    }  
}

我现在对问题的理解是,派生的Deserialize首先根据枚举的类型(即u64)映射json值,然后再尝试将其转换为十进制。因此,如果 json 表示是字符串而不是数字,它将中断。

如何让我的变体保持u64 的内部类型,但在 json 中将颜色表示为十六进制?

【问题讨论】:

  • 你能举一个你想要反序列化的 JSON 的例子吗?

标签: json enums rust serde


【解决方案1】:

您可以自定义Color 本身的反序列化:

use serde::{de, Deserialize, Serialize};

#[derive(Deserialize, Serialize, Debug)]
pub enum Color {
    Red,
    Green,
    Blue,
    #[serde(deserialize_with = "color_deserialize")]
    Custom(u64),
}

#[derive(Deserialize, Serialize, Debug)]
pub struct Config {
    #[serde(rename = "borderColor")]
    pub border_color: Color,
}

fn color_deserialize<'de, D>(deserializer: D) -> Result<u64, D::Error>
where
    D: de::Deserializer<'de>,
{
    let s: String = Deserialize::deserialize(deserializer)?;
    let without_prefix = s.trim_start_matches("#");
    match u64::from_str_radix(without_prefix, 16) {
        Ok(res) => Ok(res),
        Err(e) => Err(de::Error::custom(format!(
            "Failed to deserialize color: {}",
            e
        ))),
    }
}

fn main() {
    let c = serde_json::from_str::<Config>(
        r##"{ "borderColor": { "Custom": "#bdcebe" }}"##,
    );
    println!("{:#?}", c);
}

当然你还必须实现另一半,即序列化。

【讨论】:

    猜你喜欢
    • 2018-10-11
    • 1970-01-01
    • 2023-02-22
    • 2016-10-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-04
    • 2019-06-24
    相关资源
    最近更新 更多