如何使用Serde反序列化包含空值的JSON文件? [英] How to deserialize a JSON file which contains null values using Serde?

查看:188
本文介绍了如何使用Serde反序列化包含空值的JSON文件?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想反序列化来自 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆