使用 Rust 中的 Serde 从 json 中提升嵌套值可能是可选的

Lifting nested values from json that might be optional using Serde in Rust

我正在使用这个解决方案:

从嵌套的 json 结构中提高浮点值:

这是JSON

"activitiesWon": {
    "statId": "activitiesWon",
    "basic": {
        "value": 3.0,
        "displayValue": "3"
    }
},

这里是数据结构和客户解串器:

#[derive(Serialize, Deserialize, Debug, Default, Clone, Copy)]
pub struct PvpStatsData {
    #[serde(rename = "activitiesWon", deserialize_with="property_to_float")]
    pub activities_won:f32,
}

pub fn property_to_float<'de, D>(deserializer: D) -> Result<f32, D::Error>
    where D: serde::de::Deserializer<'de>,
{
    #[derive(Deserialize)]
    struct Outer {
        pub basic: Inner,
    }
    
    #[derive(Deserialize)]
    struct Inner {
        pub value: f32,
    }

    let helper = Outer::deserialize(deserializer)?;
    Ok(helper.basic.value)
}

效果很好。但是,某些结构/属性可能不存在,因此它们的字段签名看起来像这样,使用自定义反序列化器 returns 一个选项,或 None:

#[derive(Serialize, Deserialize, Debug, Default, Clone, Copy)]
pub struct PvpStatsData {
    #[serde(rename = "bestSingleGameKills", deserialize_with="property_to_option_float")]
    pub best_single_game_kills:Option<f32>,
}

pub fn property_to_option_float<'de, D>(deserializer: D) -> Result<Option<f32>, D::Error>
    where D: serde::de::Deserializer<'de>,
{
    println!("PARSER");
    #[derive(Deserialize, Debug, )]
    struct Outer {
        pub basic: Inner,
    }
    
    #[derive(Deserialize, Debug, )]
    struct Inner {
        pub value: f32,
    }

    Option::<Outer>::deserialize(deserializer).map(|o:Option<Outer>| match o {
        Some(e) => {
            println!("{:?}", e);
            Some(e.basic.value)
        },
        None => None,
    })
}

但是,在解析时,如果 json 中不存在 属性,则会出现解析错误:

serde_json::Error : Error("missing field `bestSingleGameKills`", line: 1, column: 4358)

并且我的自定义反序列化方法从未被调用。

谁知道为什么不调用反序列化方法?和/或当 属性 不存在时如何调用它?我还有其他可以处理可选结果的反序列化器,但我怀疑这与嵌套 json 和选项的组合有关。

我在这里发布了示例的游乐场: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=022d7ca3513e411644d186518d177645

(只需取消注释第二个 json 块即可查看问题)

default 字段属性应该有效(我假设您同意 best_single_game_kills 默认为 None,但 json 中不存在它)。

#[derive(Deserialize, Debug, Default, Clone, Copy)]
pub struct PvpStatsData {
    #[serde(default, rename = "activitiesWon", deserialize_with="property_to_float")]
    pub activities_won:f32,
    
    #[serde(default, rename = "bestSingleGameKills", deserialize_with="property_to_option_float")]
    pub best_single_game_kills:Option<f32>,
}

https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=a50748db2fb585a9430371a6ecd10f82