有没有办法使用 Rust 的 serde / serde_json 到 "patch" 结构?

Is there a way to use Rust's serde / serde_json to "patch" a structure?

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

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

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

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);
}