Skip to content

Serializer 协议

This content is not available in your language yet.

序列化时 Rust 值已经存在,因此控制权在 Serialize 实现:它按自己的语义结构调用格式提供的 Serializer 方法。

先给答案:序列化时 Rust 值已经存在,因此控制权在 Serialize 实现:它按自己的语义结构调用格式提供的 …

Section titled “先给答案:序列化时 Rust 值已经存在,因此控制权在 Serialize 实现:它按自己的语义结构调用格式提供的 …”

序列化时 Rust 值已经存在,因此控制权在 Serialize 实现:它按自己的语义结构调用格式提供的 Serializer 方法。 正文沿“调用方向 -> 为什么复合类型返回状态对象 -> 关联类型而非 dyn SerializeSeq”展开:先确认入口和状态归属,再跟踪控制流或数据流的推进,最后落到对外可观察的结果。

主要失效边界集中在“错报 seq 长度、collectstr 滥用、human-readable 分支变化 schema”这些场景。它们破坏的是容量、顺序、并发或生命周期前提;排查时应先确认状态是否仍由正确对象持有,再核对推进条件和清理路径。

MyStruct::serialize(serializer)
-> serializer.serialize_struct("MyStruct", 2)
-> state.serialize_field("id", &self.id)
-> state.serialize_field("name", &self.name)
-> state.end()

Serialize trait 位于 serde_core/src/ser/mod.rs:234-252,唯一核心方法接收泛型 S: Serializer。Serializer 在 :355-406 定义 Ok、Error 和七类复合状态关联类型,然后提供所有数据模型入口。

serialize_seq 返回 Self::SerializeSeq(ser/mod.rs:1006),map 与 struct 分别返回 SerializeMap、SerializeStruct。这些 trait 定义于 :1518、:1811、:1907,都以 end(self) 收口。

状态对象允许格式:

  • 先写长度或开括号;
  • 在元素之间写分隔符;
  • 维护首元素标记;
  • 缓存 map key;
  • 结束时写尾部或校验长度。

每种格式可返回自己的具体状态类型,编译器单态化后能内联 serialize_element 和 end。不需要虚调用,也不强制堆分配。若某种复合形态不可能出现,可使用 ser::Impossible(serde_core/src/ser/impossible.rs)作为关联类型。

序列化错误 trait 由宏生成,入口在 ser/mod.rs:148 附近,核心是 custom(Display)。格式错误可以保留 IO、语法和数据范围信息;数据结构实现不依赖具体错误类型。

替代方案:fn serialize(&self, &mut dyn Serializer)。

为什么不选:Serializer 含关联类型和泛型方法,且动态分派会阻止大量内联;对象安全还会限制协议表达。

证据:Serialize::serialize<S> 和各复合状态均使用静态泛型(ser/mod.rs:234-252、:1518 之后),使类型+格式组合在编译期专门化。

Serializer 可通过 is_human_readable(ser/mod.rs:1459-1462)提示格式偏文本还是紧凑二进制。类型可据此选择字符串或紧凑表示,但这会让同一类型跨格式的 wire shape 不完全一致,应谨慎用于长期协议。

场景 现象 原因 规避
错报 seq 长度 格式错误或输出非法 end 时长度不一致 不确定时传 None,或严格计数
collect_str 滥用 临时格式化分配 走 Display 文本路径 数字/bytes 用专用方法
human-readable 分支变化 schema 跨格式不兼容 表示随格式能力变化 外部协议固定明确表示
自定义 impl 忽略字段属性语义 与 derive 不一致 手写逻辑漂移 用测试 token 固化形状

复合操作返回专用状态对象,是“builder 即协议状态机”的常用模式。关联类型让每个实现拥有零分配的状态布局,同时调用方只依赖统一 trait。

面试锚点

  • Serializer 为什么有这么多关联类型?
  • SerializeSeq::end 的作用是什么?
  • 静态泛型如何帮助零成本抽象?