使用 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>,
}
我正在使用这个解决方案:
从嵌套的 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>,
}