Rust in Everything
基于 serde 1.0.229

常见坑

每一章对着一个报错或一个现象:先用最小的程序把它复现出来(输出是 M2 Max、macOS、rustc 1.99.0 上的原文),再到源码里找它从哪一行来,最后给出修法和检查办法。机制在前面几部分讲过的,这里只链过去,不再重复。

  1. data did not match any variant of untagged enum Shape:untagged 只留一句话,每个变体为什么失败都被丢了;读成 Value 再逐个变体 from_value 才看得到真正的错误;变体顺序还会让输入读成功但读错。
  2. invalid type: string "1", expected u32:JSON 里的数字写成了字符串,serde_json 照 deserialize_u32 的提示只读数字;只收字符串用 DisplayFromStr,数字和字符串都收用 PickFirst<(_, DisplayFromStr)> 或自写调 deserialize_any 的 deserialize_with;数字键 map 进了缓冲也报这句。
  3. missing field x:只有字段类型自己调 deserialize_option 才会缺省成 None;deserialize_with、newtype 包着的 Option、Value、Vec 缺了都报错,要加 default。
  4. invalid type: string "...", expected a borrowed string:&str 字段遇到带转义的字符串借不成;from_reader 配 &str 在编译期就被拒;改用 String 或 Cow 加 borrow。
  5. unknown field kind:flatten 加 deny_unknown_fields 能编译,效果却因 flatten 的对象而异,flatten 内部标签 enum 时连合法输入都失败;flatten 的 Option 出错时静默成 None。
  6. u128 is not supported:Content 没有 128 位整数,内部标签、flatten 里的 u128 读不回,untagged 只剩 no match;toml 和 serde_urlencoded 读 u128 也报这句。
  7. Bincode does not support the serde::Deserializer::deserialize_any method:bincode、postcard 只能按提示读:内部标签、相邻标签、untagged、Value 能写不能读,flatten 写不出来,skip_serializing_if 读错位。
  8. key must be a string:JSON 对象的键只能是字符串,元组、struct、None 当键报错,NaN 键报 float key must be finite;整数、bool 键会被写成字符串。
  9. recursion limit exceeded:serde_json 最多嵌套 127 层;unbounded_depth 能关掉限制,但嵌套深了递归会栈溢出。
  10. the trait bound Rc<std::string::String>: serde::Serialize is not satisfied:Rc / Arc 的实现在 rc feature 后面,因为序列化、反序列化都不保留共享,读回来是多份拷贝。
  11. from_reader 读文件很慢:serde_json 不缓冲,直接给 File 时每个字节一次 read 系统调用,1.28 MB 用 483 ms;包一层 BufReader 是 4 ms,read_to_end 加 from_slice 是 3 ms。
  12. 浮点数往返后不相等:默认的浮点解析不是正确舍入,[0, 1) 的数约 10% 读回来差最后一位;开 float_roundtrip 归零;NaN 和无穷写成 null,读不回 f64。
  13. attempt to subtract with overflow,或者 [],1,2]:手写 Serialize 声称 serialize_seq(Some(0)) 却写进元素,to_string 写出非法 JSON,to_string_pretty 在 debug 下 panic、release 下无限写缩进。
  14. the trait bound Post: serde::Serialize is not satisfied(明明 derive 了):依赖树里同时有 serde 0.9 和 1.x,类型实现的是旧版的 trait,rustc 只说「名字相近」;serde 和 serde_derive 版本不配则在 cargo 解析阶段就失败。

按三条主线(怎么读这一卷)分:

出在哪里坑
序列化主线:类型把数据推给 Serializer8 键必须是字符串、12 NaN 写成 null、13 谎报长度
反序列化主线:格式驱动 Visitor2 类型不符、3 缺字段、4 借不到、9 递归上限、11 from_reader 慢、12 浮点解析
缓冲主线:先读成 Content 再重放1 untagged、5 flatten、6 u128、7 二进制格式
不在主线上:编译期 trait 不满足10 Rc、14 两个 serde
flowchart TB
  q{碰到了什么}
  q -->|编译错误| ce{"trait 不满足"}
  ce -->|"Rc 或 Arc"| p10["10 rc feature"]
  ce -->|"明明 derive 了"| p14["14 两个 serde"]
  q -->|反序列化报错| de{哪种}
  de -->|"untagged enum"| p1["1 untagged"]
  de -->|"invalid type"| p2["2 或 4"]
  de -->|"missing field"| p3["3 缺字段"]
  de -->|"unknown field"| p5["5 flatten"]
  de -->|"deserialize_any"| p7["7 二进制格式"]
  de -->|"recursion limit"| p9["9 递归上限"]
  q -->|序列化报错| p8["8 键必须是字符串"]
  q -->|"结果不对或很慢"| r{哪种}
  r -->|读文件慢| p11["11 from_reader"]
  r -->|浮点不相等| p12["12 浮点往返"]
  r -->|"JSON 非法或 panic"| p13["13 谎报长度"]

💬 关联讨论

发起讨论
加载中...