首页 > 解决方案 > 有没有办法使用 Rust 的 serde / serde_json 来“修补”一个结构?

问题描述

是否有一种相当简单的方法可以使用 serde/serde_json 来获取现有结构并仅更新 JSON 中存在的那些字段?这基本上相当于在运行时而不是在编译时通过实现 Default trait 或默认值生成器函数来设置默认值。

当您有一个 RESTful API 时,这似乎是一个非常常见的用例,您希望在其中提交更新到状态,只修改指定的字段并保持未指定的字段不变。

我可以通过反序列化为动态值类型,然后进行大匹配或 if/else 块来更新字段来做到这一点,但这既冗长又丑陋。我想知道 serde 是否有什么可以处理的。

标签: rustserde

解决方案


Serde 不支持这样的东西。如果我需要这样做,我可能会创建一个并行结构,其中所有字段都是可选的:

use serde::Deserialize;

#[derive(Deserialize)]
pub struct MyData {
    foo: String,
    bar: u64,
    wibble: bool,
}

#[derive(Deserialize)]
pub struct MyDataPatch {
    foo: Option<String>,
    bar: Option<u64>,
    wibble: Option<bool>,
}

impl MyData {
    pub fn patch(&mut self, update: MyDataPatch) {
        if let Some(foo) = update.foo {
            self.foo = foo;
        }
        if let Some(bar) = update.bar {
            self.bar = bar;
        }
        if let Some(wibble) = update.wibble {
            self.wibble = wibble;
        }
    }
}

这是更多的代码重复,但运行时开销更少。

如果我有很多这些,那么我会用宏生成所有这些,而不是手动编写。您可以使用可派生的特征来做到这一点,例如:

trait Patch {
    type Patch; // Self with all optional fields
    fn patch(&mut self, patch: &Self::Patch);
}

推荐阅读