附录 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 结果。
(End)