附录 C:派生特质
Appendix C: Derivable Traits
本书的多个不同地方,咱们都曾讨论过 derive
属性,咱们可将其应用到结构体或枚举定义。derive
属性会在咱们以 derive
语法注解的类型上,生成将以某个特质自身默认实现,而实现该特质的代码。
在这个附录中,咱们会提供到标准库中,咱们可以与 derive
一起使用的全部特质的参考。以下各个小节均会讲到:
-
此特质将启用那些操作符与方法;
-
由
derive
所提供到的该特质实现会做些什么; -
实现该特质对那个类型意味着什么;
-
允许及不允许实现该特质的情况;
-
需要该特质操作的示例。
若咱们想要不同于由 derive
属性所提供的行为,请参考 标准库文档,了解如何亲自实现各个特质的详细信息。
这里列出的这些特质,只是一些由标准库所提供的,可使用 derive
实现于咱们类型上的那些。定义在标准库中别的一些特质,则没有什么合理的默认行为,因此是否要以对于咱们正尝试完成的东西有意义的方式,实现他们就取决于咱们自己了。
不能派生的一个特质示例便是 Display
,其为终端用户处理格式化。咱们应始终要考虑将某个类型显示给用户的恰当方式。终端用户应被允许看到该类型的哪些部分?他们会发现哪些部分是相关的?数据的何种形式才是与他们最为密切相关的?Rust 编译器并无这种见解,因此他就无法为咱们提供到恰当的默认行为。
这个附录中所提供到的派生特质清单并不详尽:库可以为他们自己的特质实现 derive
,从而领导咱们可使用 derive
的特质清单为真正开放的。实现 derive
设计到使用程序性宏,这在第 19 章的 “关于宏” 小节讲到过。
输出给编程者的 Debug
Debug
for Programmer Output
Debug
特质实现了格式字符串中的格式化,所谓格式字符串,即咱们通过在 {}
里添加 :?
所表示的。
Debug
特质允许咱们为调试目的打印某种类型的实例,如此咱们以及用到咱们类型的其他编程者,就可以在程序执行的某个特定时刻,就其某个实例加以探查。
在比如用到 assert_eq!
宏中等情况下,Debug
特质便是要求使用的。assert_eq!
这个宏在相等断言失败时,就会打印出作为参数所给到的两个实例值,如此编程者就可以看到为何这两个实例不相等。
用于相等比较的 PartialEq
与 Eq
PartialEq
特质允许咱们比较某种类型的两个实例,来检查他们是否相等,并实现 ==
与 !=
运算符的应用。
对 PartialEq
进行派生,就会实现 eq
方法。当 ParitalEq
实在结构体上实现的时,只有在两个实例的 全部 字段都相等时,他们才是相等的,且在有任何字段不等时,两个实例便不相等。当在枚举上派生时,枚举的各个变种与自身相等,而不等于其他任何变种。
在使用需要能够比较某个类型的两个实例是否相等的 assert_eq!
宏时,就需要这个 PartialEq
特质。
而 Eq
特质则没有方法。他的目的是要表明,所注解的类型的每个值,其值都等于他自身。尽管并非所有实现 PartialEq
的类型都可以实现 Eq
,但 Eq
特质却只可应用到那些同时实现了 PartialEq
的类型。这方面的一个示例,便是浮点数类型:浮点数的实现,就表明两个非数字(the not-a-number, NaN
)的值,是各自不相等的。
要求 Eq
的一个示例,就是 HashMap<K, V>
中的那些键,如此 HashMap<K, V>
就可以区分出两个键是否一致。
用于排序比较的 PartialOrd
与 Ord
PartialOrd
and Ord
for Ordering Comparisons
PartialOrd
特质实现为排序目的,而比较某种类型的那些实例。实现了 PartialOrd
的类型,便可与 <
、>
、<=
及 >=
符号一起使用了。咱们只能对那些同时实现了 PartialEq
的类型,应用这个 PartialOrd
特质。
派生 PartialOrd
,会实现 partial_cmp
方法,该方法会返回一个在所给的那些值不会产生出顺序时,将为 None
的一个 Option<Ordering>
。至于即使那种类型的大多数值都可被比较,但仍不会产生出顺序的值的一个示例,便是非数字(NaN
)浮点值。在任何浮点数和非数字浮点值下调用 partial_cmp
,都会返回 None
。
在于结构体上派生时,PartialOrd
会通过字段出现在结构体定义中的顺序,比较每个字段中的值,比较两个实例。而当于枚举上派生时,枚举定义中较早声明的枚举变种,被当作是小于后面所列出的那些变种的。
在比如会产生出由范围表达式所指定范围中一个随机数的, rand
代码箱的 gen_range
方法来说,PartialOrd
特质便是需要的。
Ord
特质实现对所注解类型的任何两个值,将存在有效顺序的掌握。Ord
特质会实现 cmp
方法,由于有效排序将始终可行,因此该方法返回的是 Ordering
而非 Option<Ordering>
。咱们只可对那些同时实现了 PartialOrd
及 Eq
(而 Eq
要求 PartialEq
) 的类型,实现这个 Ord
特质。当于结构体及枚举上派生 Ord
时,cmp
就会以与 PartialOrd
下 partial_cmp
的派生实现同样方式行事。
要求 Ord
的一个示例,即为将一些值存储在 BTreeSet<T>
这种根据值的排序,而存储数据的数据结构中时。
用于复制值的 Clone
与 Copy
Clone
and Copy
for Duplicating Values
Clone
特质实现了显式创建值的深拷贝,而该复制过程则可能涉及运行一些任意代码,arbitary code,与拷贝内存堆数据。请参阅第 4 章中 “变量与数据交互方式:克隆” 小节,了解更多有关 Clone
的信息。
派生 Clone
会实现 clone
方法,当对整个类型实现了这个方法时,其就会在该类型的各个部分上调用 clone
。这意味着类型要派生 Clone
其中的全部字段或值,都必须同时实现 Clone
。
需要 Clone
特质的一个示例,便是在切片上调用 to_vec
方法时。切片不持有其包含的那些类型实例,但自 to_vec
所返回的那个矢量值,却将需要持有他的那些实例,从而 to_vec
会调用各个条目上的 clone
。因此,存储在切片中的类型,就必须实现 Clone
。
Copy
特质实现了只通过拷贝存储在栈上的二进制位,而复制某个值;任意代码并无必要。请参阅第 4 章中 “唯栈数据:拷贝”,了解更多有关 Copy
的信息。
Copy
特质没有定义阻止编程者过载那些方法,及破坏不会有任意代码运行这个假设的任何方法。那样的话,所有编程者就都可以假定,拷贝值将会非常快。
咱们可在其组成部分都实现了 Copy
的任何类型上派生 Copy
特质。由于实现 Copy
的类型,都有着执行与 Copy
同样任务的一个 Clone
的简单实现,因此实现 Copy
的类型必须同时实现 Clone
。
很少需要 Copy
特质;实现了 Copy
的类型,有着可供选择的优化方案,意味着咱们不必调用 clone
,而调用 clone
会令到代码更简洁。
对于 Copy
下每种可能情况,咱们都可同时以 Clone
完成,除了代码可能更慢,或在一些地方不得不使用 clone
。
用于将值映射到固定大小值的 Hash
Hash
for Mapping a Value to a Value of Fixed Size
Hash
特质实现了取某种任意大小类型的实例,并通过使用散列函数,将那个实例映射到固定大小的值。派生 Hash
会实现 hash
方法。hash
放的派生实现,会将在该类型各个组成部分上调用 hash
的结果结合起来,这就意味着类型要派生 Hash
,那么其全部字段,都必须同时实现 Hash
。
要求 Hash
的一个示例,便是为了高效地存储数据,而在 Hash<K, V>
中存储那些键时。
用于默认值的 Default
Default
for Default Values
Default
特质实现了为类型创建出一个默认值。派生 Default
会实现 default
函数。default
函数的派生实现,会在类型的各个部分上调用 default
函数,意味类型要派生 Defualt
,其中的全部字段或值,都必须同时实现 Default
。
Default::default
函数,通常是与第 5 章中 “使用结构体更新语法从其他实例创建出实例” 小节里曾讨论过的结构体更新语法结合使用的。咱们可以定制结构体的几个字段,并在随后通过使用 ..Default::default()
,为其余字段设置并使用默认值。
在 Option<T>
实例上使用 unwrap_or_default
方法时,便是需要 Default
特质的一个示例。当那个 Option<T>
为 None
时,方法 unwrap_or_default
就将返回存储在 Option<T>
中,那个类型 T
的 Default::default
结果。