我想使用Serde对Bowserinator on github中的化学元素JSON文件进行反序列化.为此,我创建了一个包含所有所需字段的 struct ,并导出了所需的宏:

#[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,
}

在到达包含"null"值的字段之前,这种方法可以正常工作.

我得到的错误信息是该字段为{ code: Message("invalid type: unit value, expected a string"), line: 8, column: 17 }.

我用#[serde(default)]宏做了实验.但这只适用于JSON文件中缺少字段的情况,而不适用于有null值的情况.

我喜欢用标准宏进行反序列化,避免编写访问者特性.我错过了什么把戏吗?

推荐答案

发生反序列化错误的原因是 struct 定义与传入对象不兼容:color字段也可以是null,也可以是字符串,但如果将该字段的类型设置为String,则程序将始终需要字符串.这是默认行为,这是有道理的.请注意,String(或其他容器,如Box)在 rust 迹中不能"为零".至于不触发默认值的null值,Serde就是这样工作的:如果对象字段不在那里,它会工作,因为您添加了默认字段属性.另一方面,值为null的字段" colored颜色 "根本不等于没有字段.

解决这个问题的一种方法是调整应用程序的规格,使其接受null | string,正如@user25064的答案所指定的:

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Element {
    color: Option<String>,
}

Playground with minimal example

另一种方法是为字段编写我们自己的反序列化 routine ,它将接受null并将其转换为String类型的其他内容.这可以通过属性#[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())
        })
}

Playground

另见:

Rust相关问答推荐

Rust为什么应用于引用的操作符可以强制,而具有显式类型的let则不能?

有没有方法处理rust中嵌套的ok_or()?

关于如何初始化弱 struct 字段的语法问题

铁 rust 中的共享对象实现特征

告诉Rust编译器返回值不包含构造函数中提供的引用

在本例中,为什么我不能一次多次borrow 可变变量?

将一个泛型类型转换为另一个泛型类型

Rust proc_macro 和 syn:解析空格

随机函数不返回随机值

Rust 并行获取对 ndarray 的每个元素的可变引用

如何从borrow 的异步代码运行阻塞代码?

有什么办法可以追踪泛型的单态化过程吗?

是否可以通过可变引用推进可变切片?

为什么我不能克隆可克隆构造函数的Vec?

只有一个字符被读入作为词法分析器的输入

您如何使用枚举反序列化字符串,其中任何其他值反序列化为新类型变体同时保留字符串?

为什么我可以从读取的可变自引用中移出?

为什么我可以在没有生命周期问题的情况下内联调用 iter 和 collect?

有没有办法在 Rust 中对 BigInt 进行正确的位移?

HashMap entry() 方法使borrow 的时间比预期的长