跳转到内容

Serde 面试专题

Serde 面试的核心不是会写 #[derive],而是能否说明类型侧、格式侧、数据模型和生命周期如何解耦。

先给答案:Serde 面试的核心不是会写 [derive],而是能否说明类型侧、格式侧、数据模型和生命周期如何解耦

Section titled “先给答案:Serde 面试的核心不是会写 [derive],而是能否说明类型侧、格式侧、数据模型和生命周期如何解耦”

Serde 面试的核心不是会写 [derive],而是能否说明类型侧、格式侧、数据模型和生命周期如何解耦。 正文沿“1. Serde 为什么不是 JSON 库 -> 2. 为什么适配复杂度是 N+M -> 3. 序列化和反序列化为什么方向相反”展开:先确认入口和状态归属,再跟踪控制流或数据流的推进,最后落到对外可观察的结果。

主要失效边界集中在“untagged enum 为什么慢且错误信息差、借用反序列化失败怎么排查”这些场景。它们破坏的是容量、顺序、并发或生命周期前提;排查时应先确认状态是否仍由正确对象持有,再核对推进条件和清理路径。

Serde 定义类型与格式交互的 trait;JSON parser/writer 在 serde_json。类型实现 Serialize/Deserialize,格式实现 Serializer/Deserializer。

N 种数据类型只实现统一数据模型,M 种格式也只实现统一数据模型,不需要每个类型直接适配每个格式。入口:ser/mod.rs:234、:355、de/mod.rs:554、:945。

3. 序列化和反序列化为什么方向相反

Section titled “3. 序列化和反序列化为什么方向相反”

序列化时值知道自身结构,主动调用 Serializer;反序列化时格式掌握输入游标,目标类型提供 Visitor,由格式边解析边驱动构造。

4. 为什么 Serializer 有多个复合关联类型

Section titled “4. 为什么 Serializer 有多个复合关联类型”

seq、tuple、map、struct 的格式状态不同。关联类型让格式返回具体零分配 builder,并在 end 时收口,而不是统一装箱。

Visitor 的 visit_map 接收 MapAccess,循环 next_key_seed / next_value_seed,检查重复和缺失字段后构造目标。源码:de/mod.rs:1837-1970。

它表示 Deserializer 可借出的输入数据生命周期。visit_borrowed_str(&'de str) 能让结果引用原输入;DeserializeOwned 则要求结果不借用任何特定输入。

不是。serde_derive 在编译期读取 syn AST,生成普通 trait impl。运行时没有字段反射表。入口:serde_derive/src/ser.rs:13、de.rs:25。

8. untagged enum 为什么慢且错误信息差

Section titled “8. untagged enum 为什么慢且错误信息差”

通常先把输入读成 Content,再按变体顺序反复尝试反序列化;失败上下文被多个候选合并。源码:de/enum_untagged.rs:46-47。

9. deserialize_any 为什么不适合所有格式

Section titled “9. deserialize_any 为什么不适合所有格式”

非自描述二进制格式无法从裸字节判断目标类型,必须由目标调用 deserialize_u32、deserialize_tuple 等 typed method。

trait 胶水通过泛型、关联类型和单态化通常可被内联,不强制动态分派或中间 Value;不代表字符串解码、容器分配、untagged 回溯没有成本。

Deserializer 是否支持 borrowed visitor
-> 输入 buffer 是否活得够久
-> 字符串是否有转义需要解码
-> 上层 API 是否要求 DeserializeOwned
-> 字段属性是否走 Content 中间层

Serde 用格式无关数据模型连接 Rust 类型与数据格式,用 Serializer 的静态状态对象完成写出,用 Deserializer+Visitor 流式构造值,再由 derive 在编译期生成大多数胶水代码。