使用借用的结构字段派生“反序列化”

Derive `Deserialize` with borrowed struct field

我正在尝试在借用内容的结构上派生 Deserialize

#[macro_use]
extern crate serde_derive;
use std::net::SocketAddr;

#[derive(Hash, Eq, PartialEq, Debug, Clone, Serialize, Deserialize)]
pub struct MyS<'a> {
    pub addr: &'a SocketAddr,
}

rust playground

我得到以下编译错误:

error[E0277]: the trait bound `&'a std::net::SocketAddr: _::_serde::Deserialize<'_>` is not satisfied
 --> src/lib.rs:7:5
  |
7 |     pub addr: &'a SocketAddr,
  |     ^^^ the trait `_::_serde::Deserialize<'_>` is not implemented for `&'a std::net::SocketAddr`
  |
  = help: the following implementations were found:
            <std::net::SocketAddr as _::_serde::Deserialize<'de>>
  = note: required by `_::_serde::de::SeqAccess::next_element`

我可以通过哪些不同的方式让这个结构实现 Deserialize 一段时间?

注意:我实际上并不要求反序列化是零拷贝,这只是一个很好的选择

你不能这样做,原因如下:

Serde 允许 zero-copy 某些类型的反序列化。在这种情况下,数据是从 Deserializer 借用的,后者又借用或拥有某种缓冲区。由于 &[u8]&str 从根本上讲都是字节流,因此可以将它们反序列化为缓冲区中的引用。 serde docs 中解释了这是如何工作的,但它从根本上要求 Rust 类型的布局与您正在反序列化的缓冲区中存在的数据完全相同。

但是,在您的情况下,您想要反序列化 SocketAddr。问题是缓冲区中的数据与您要借用的数据的形式不同。 Serde 通过 DisplaySocketAddrs 序列化为字符串,例如 this implemention for SocketAddrV4。但是 SocketAddr 本身存储为一个 32 位整数和一个 16 位整数。你不能把一个当作另一个来借;需要进行某种解析,然后有人需要拥有结果数据。 Serde 逻辑上让您的结构拥有该数据。即使在二进制序列化中,也不能保证序列化数据的布局与结构的布局匹配,因此需要进行解析。

这是通过 Deserialize serde 提供的实现在类型系统中编码的。 This page 有完整列表。您可以看到 &'a str 的实现,其中 Deserializer ('de) 的生命周期超过 'a。没有实现对大多数其他类型的引用,包括 &SocketAddr.

这个 serde 问题 linked by PitaJ 显示了一个很好的最小代码示例。