附录 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. 可带走的¶
- derive 合同:字段递归;字段全实现才能 derive。
- NaN 使 PartialEq/PartialOrd 成为"Partial";Eq/Ord 标记完备语义。
- HashMap 键要 Eq + Hash;BTree 结构要 Ord。
- Clone 显式可能贵;Copy 隐式一定便宜、无方法、须搭 Clone。
- Display 无 derive——"给人看"没有默认答案。
- unwrap_or_default / ..Default::default() 是 Default 的两个主战场。
6. 原文地图¶
| 主题 | 原书章 | 原文位置 |
|---|---|---|
| derive 合同与清单总述 | Appendix C: Derivable Traits | text/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」) |
-
出处:「Appendix C: Derivable Traits」第 4 段(
text/31-apx-c-appendix-c-derivable-traits.txt:4,搜「derive attribute」)。 ↩↩ -
出处:「Appendix C: Derivable Traits」第 63 段(
text/31-apx-c-appendix-c-derivable-traits.txt:63,搜「NaN」)。 ↩↩ -
出处:「Appendix C: Derivable Traits」第 67 段(
text/31-apx-c-appendix-c-derivable-traits.txt:67,搜「PartialOrd and Ord」)。 ↩↩ -
出处:「Appendix C: Derivable Traits」第 95 段(
text/31-apx-c-appendix-c-derivable-traits.txt:95,搜「Clone and Copy」)。 ↩↩ -
出处:「Appendix C: Derivable Traits」第 24 段(
text/31-apx-c-appendix-c-derivable-traits.txt:24,搜「Display」)。 ↩