如何使用Serde反序列化包含空值的JSON文件? [英] How to deserialize a JSON file which contains null values using Serde?
问题描述
我想反序列化来自 Bowserinator上的化学元素JSON文件github 使用Serde.为此,我创建了一个具有所有必需字段的结构,并派生了所需的宏:
I want to deserialize the chemical elements JSON file from Bowserinator on github using Serde. For this I created a structure with all the needed fields and derived the needed macros:
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Element {
name: String,
appearance: String,
atomic_mass: f64,
boil: f64,
category: String,
#[serde(default)]
color: String,
density: f64,
discovered_by: String,
melt: f64,
#[serde(default)]
molar_heat: f64,
named_by: String,
number: String,
period: u32,
phase: String,
source: String,
spectral_img: String,
summary: String,
symbol: String,
xpos: u32,
ypos: u32,
}
这很好,直到到达包含空"值的字段为止.
例如.表示氦气中的"color": null,
字段.
This works fine until it gets to fields which contain a "null" value.
E.g. for the field "color": null,
in Helium.
此字段显示的错误消息是{ code: Message("invalid type: unit value, expected a string"), line: 8, column: 17 }
.
The error message I get is { code: Message("invalid type: unit value, expected a string"), line: 8, column: 17 }
for this field.
我尝试了#[serde(default)]
宏.但这仅在JSON文件中缺少该字段时有效,而在没有null
值时则无效.
I experimented with the #[serde(default)]
Macro. But this only works when the field is missing in the JSON file, not when there is a null
value.
我喜欢对标准宏进行反序列化,从而避免对访问者特征进行编程.我有想念的把戏吗?
I like to do the deserialization with the standard macros avoiding to program a Visitor Trait. Is there a trick I miss?
推荐答案
发生反序列化错误,因为结构定义与传入的对象不兼容:color
字段也可以是null
,也可以是字符串,但是为该字段提供类型String
会强制您的程序始终期望使用字符串.这是默认行为,这是有道理的.请注意,String
(或其他容器,例如Box
)在Rust中不是可为空"的.至于null
值而不触发默认值,这就是Serde的工作方式:如果object字段不存在,则它将起作用,因为您已经添加了默认的field属性.另一方面,值为null
的颜色"字段根本不等于没有任何字段.
A deserialization error occurs because the struct definition is incompatible with the incoming objects: the color
field can also be null
, as well as a string, yet giving this field the type String
forces your program to always expect a string. This is the default behaviour, which makes sense. Be reminded that String
(or other containers such as Box
) are not "nullable" in Rust. As for a null
value not triggering the default value instead, that is just how Serde works: if the object field wasn't there, it would work because you have added the default field attribute. On the other hand, a field "color" with the value null
is not equivalent to no field at all.
解决此问题的一种方法是调整应用程序的规范以接受null | string
,如@ user25064的答案所指定:
One way to solve this is to adjust our application's specification to accept null | string
, as specified by @user25064's answer:
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Element {
color: Option<String>,
}
另一种方法是为该字段编写自己的反序列化例程,该例程将接受null
并将其转换为其他类型的String
.可以使用属性#[serde(deserialize_with=...)]
.
Another way is to write our own deserialization routine for the field, which will accept null
and turn it to something else of type String
. This can be done with the attribute #[serde(deserialize_with=...)]
.
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Element {
#[serde(deserialize_with="parse_color")]
color: String,
}
fn parse_color<'de, D>(d: D) -> Result<String, D::Error> where D: Deserializer<'de> {
Deserialize::deserialize(d)
.map(|x: Option<_>| {
x.unwrap_or("black".to_string())
})
}
这篇关于如何使用Serde反序列化包含空值的JSON文件?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!