编程语言研究书库

附录 C:可派生 trait 速查 — 拆解

附录 C:可派生 trait 速查

这份附录是什么: #[derive(...)] 能自动配上的全部标准库 trait,共六组。 第 5 章的 #[derive(Debug)] 只是入口;这里是全表。 记住一条总合同:派生实现 = 对类型的每个字段递归调同名方法——任何字段不支持,derive 就失败1。

1. 六组 trait 与"什么时候被要求"

组提供什么谁要求它
Debug{:?} / {:#?} 打印(开发者向)第 11 章断言宏 assert_eq! 失败时要打印左右值
PartialEq== / !=assert_eq! 本身;许多"找相等"的 API
Eq在 PartialEq 之上加自反保证(x==x 恒真)HashMap 的键
PartialOrd< > <= >=rand 的 gen_range;排序入口
Ord全序保证(任何两值可比出先后)BTreeSet/二叉搜索结构
Clone显式 .clone() 深拷贝slice::to_vec 等"转拥有"操作
Copy按位拷贝,隐式发生让赋值/传参不 move(编译器优化依据)
Hash哈希到定长值HashMap 的键
Default::default() 造默认值unwrap_or_default;..Default::default() 结构体更新

2. 三组核心辨析

PartialEq vs Eq:相等"完备"吗。 PartialEq 只承诺 == 语义可以判定,但允许某些值不相等——典型是浮点 NaN:NaN != NaN,即使跟自己比。Eq 是标记 trait,加上"自反"保证(x == x 恒真)。Eq 是 HashMap 键的要求:哈希表判键相同要靠"相等"这个关系可靠2。

PartialOrd vs Ord:次序"完备"吗。 PartialOrd 的 partial_cmp 返回 Option<Ordering>——遇到 NaN 返回 None("这俩没法排序");derive 在结构体上按字段声明顺序逐字段比,枚举按变体声明先后比。Ord 补上全序保证,cmp 直接返回 Ordering;二叉搜索树要求它3。

Clone vs Copy:拷贝的两种量级。 Clone 是显式方法调用,可能包含任意代码和堆数据复制(derive 的 clone 对每个字段调 clone)。Copy 是隐式的纯按位栈拷贝——它故意不定义任何方法,以防有人重载方法破坏"拷贝一定很快"的公共假设;实现 Copy 的前提是字段全 Copy、且已实现 Clone(Copy 就是 Clone 的平凡特例)。Copy 几乎不被"要求",它是优化和代码简洁度;Clone 能包打 Copy 的场,只是更啰嗦4。

3. 不能 derive 的:Display 是代表

Display(面向终端用户的格式化)没有 derive——"该给用户看哪些字段、用什么格式"没有合理默认,这正是第 5 章"Rust 拒绝替你猜"的那个例子。附录明确:标准库里能 derive 的只有这份清单上的;其他 trait(包括 Display)要么手写、要么用库的过程宏(第 20 章的 derive 宏生态)5。

4. 作者的判断与证据

  • derive 合同("字段递归、字段都要实现")——机制事实,逐 trait 重复申明1。
  • NaN 的"不等于自己"是 PartialEq/PartialOrd 存在的原因——机制+数学事实23。
  • Copy 无方法、防重载——设计决策,理由给了("人人可假设拷贝很快")4。

判断(我们的,不是书里的): 这份清单读起来像一张"类型语义完备度"的体检表: Partial* 系承认浮点这个世界的不完美,Eq/Ord 标记"此类型干净到可当哈希键/树键"—— derive 清单实际是 Rust 类型系统的常用不变量清单。 写新类型时照着它过一遍(需要 Eq 吗?需要 Ord 吗?),比随机加 derive 靠谱。 如果错,会错在: 对大多数业务结构体,语义正确(尤其 Hash 与 PartialEq 一致) 需要人来担保——derive 保证字段递归一致,但不保证"相等的值哈希必相等"这种跨 trait 约定 在你的语义下成立(基本类型成立,自定义语义要自己核)。

5. 可带走的

  1. derive 合同:字段递归;字段全实现才能 derive。
  2. NaN 使 PartialEq/PartialOrd 成为"Partial";Eq/Ord 标记完备语义。
  3. HashMap 键要 Eq + Hash;BTree 结构要 Ord。
  4. Clone 显式可能贵;Copy 隐式一定便宜、无方法、须搭 Clone。
  5. Display 无 derive——"给人看"没有默认答案。
  6. unwrap_or_default / ..Default::default() 是 Default 的两个主战场。

6. 原文地图

主题原书章原文位置
derive 合同与清单总述Appendix C: Derivable Traitstext/31-apx-c-appendix-c-derivable-traits.txt:4(搜「derive attribute」)
Eq 与 NaN同上text/31-apx-c-appendix-c-derivable-traits.txt:63(搜「NaN」)
PartialOrd/Ord 字段顺序同上text/31-apx-c-appendix-c-derivable-traits.txt:67(搜「PartialOrd and Ord」)
Clone vs Copy同上text/31-apx-c-appendix-c-derivable-traits.txt:95(搜「Clone and Copy」)
Hash / Default同上text/31-apx-c-appendix-c-derivable-traits.txt:125(搜「Hash for Mapping」) · text/31-apx-c-appendix-c-derivable-traits.txt:134(搜「Default for Default Values」)

Footnotes

  1. 出处:「Appendix C: Derivable Traits」第 4 段(text/31-apx-c-appendix-c-derivable-traits.txt:4,搜「derive attribute」)。 ↩ ↩2

  2. 出处:「Appendix C: Derivable Traits」第 63 段(text/31-apx-c-appendix-c-derivable-traits.txt:63,搜「NaN」)。 ↩ ↩2

  3. 出处:「Appendix C: Derivable Traits」第 67 段(text/31-apx-c-appendix-c-derivable-traits.txt:67,搜「PartialOrd and Ord」)。 ↩ ↩2

  4. 出处:「Appendix C: Derivable Traits」第 95 段(text/31-apx-c-appendix-c-derivable-traits.txt:95,搜「Clone and Copy」)。 ↩ ↩2

  5. 出处:「Appendix C: Derivable Traits」第 24 段(text/31-apx-c-appendix-c-derivable-traits.txt:24,搜「Display」)。 ↩

On this page