如何借用一个字段进行序列化,但在反序列化时创建它?

How to borrow a field for serialization but create it during deserialization?

我有这样的结构:

#[derive(Serialize, Deserialize)]
struct Thing {
    pub small_header: Header,
    pub big_body: Body,
}

我想序列化此 Thing 以通过网络发送。我已经有一个 Body 可用但 我不能移动它 (想象一下我正在用它做一些事情,我时不时地收到一个命令来暂时停止我的操作我正在做并发送我现在拥有的任何数据)并且我无法复制它(它太大了,可能有数百兆字节)。

所以我希望 Serde 借用我的序列化它,因为它不需要为此移动到结构中。如果我重写Thing来引用,显然无法推导出Deserialize!

我一直在使用的解决方法是在我的代码中使用 Arc<Body>,这样我就可以在我的正常逻辑中使用 body,当我需要序列化它时,我可以做一个便宜的克隆并将 Arc<Body> 放入结构中进行序列化。在反序列化期间,Serde 将创建一个新的 Arc,引用计数为 1.

这仍然涉及分散 Arc 我的代码,这不是很好,更不用说不必要的(虽然很小)运行时成本。此用例的正确解决方案是什么?

有趣的是,如果我不必发送 header,那么这将是 non-issue,因为我可以按引用序列化和按值反序列化,但是存在a header 使这成为不可能。我觉得我遗漏了一些关于 Serde 如何在这里借用数据的信息......

您可以使用 Cow,它在序列化时为 Cow::Borrowed,在反序列化时反序列化为 Cow::Owned

use std::borrow::Cow;

#[derive(Serialize, Deserialize)]
struct Thing<'a> {
    small_header: Header,
    big_body: Cow<'a, Body>,
}

或者,您可以将序列化和反序列化为两个独立的数据结构。

#[derive(Serialize)]
struct SerializeThing<'a> {
    small_header: Header,
    big_body: &'a Body,
}

#[derive(Deserialize)]
struct DeserializeThing {
    small_header: Header,
    big_body: Body,
}

请记住,serde 始终分配(默认)(https://github.com/serde-rs/serde/issues/1852)。

要确保您确实在借用,请使用#[serde(borrow)]。

例如:

#[derive(Serialize, Deserialize)]
struct Thing<'a> {
    small_header: Header,
    #[serde(borrow)]
    big_body: Cow<'a, Body>,
}