1.17.1. 一致性

一致性意味着对于给定的类型和方法,该方法在该类型上的实现只有一种正确的选择。

孤儿规则意味着只要 trait 或类型中任意一方位于本地 crate,你就可以为该类型实现该 trait。 例如:

  • 本地定义的类型可以实现 Debug trait
  • 你可以为 bool 实现本地定义的 trait
  • 你不能为 bool 实现 Debug,因为双方都不在本地

孤儿规则存在例外,我们将在下文讨论。

1.17.2. 毯式实现

毯式实现(也称通用实现)是指 Rust 允许为满足 trait bound 的所有类型提供默认实现。

其模板为:

impl<T> MyTrait for T where T: ...

Enter fullscreen mode Exit fullscreen mode

这意味着为实现某个 trait 的所有类型实现 MyTrait

例如:

impl<T: Display> ToString for T {}

Enter fullscreen mode Exit fullscreen mode

这意味着为实现 Display 的所有类型实现 ToString

此示例尚未使用模板形式书写。使用模板形式应为:

impl<T> ToString for T where T: Display {}

Enter fullscreen mode Exit fullscreen mode

注意:只有定义该 trait 的 crate 才允许使用毯式实现。向现有 trait 添加毯式实现属于破坏性变更。

1.17.3. 基础类型

某些类型非常基础,我们需要允许任何人对其实现 trait,即使这会违反孤儿规则。这些类型被标记为 #[fundamental],目前包括 &T&mut TBox<T>Pin<P>

  • 额外说明:Pin<P> 的主要目的是确保值无法被移动,即阻止 std::mem::replacestd::mem::swapstd::mem::take 等操作改变值的物理地址
  • 就孤儿规则而言,这些类型在进行孤儿规则检查前会被视作已擦除

注意:对基础类型使用毯式实现同样被视为破坏性变更。

1.17.4. 覆盖实现

有时你需要为外部类型实现外部 trait,这被称为覆盖实现。它利用了孤儿规则的一个狭窄例外:允许在非常特定的情况下为外部类型实现外部 trait。

注意:覆盖实现既可指 Covered Implementation,也可指 Override Implementation。此处指 Covered Implementation。Override Implementation 指结构体在实现 trait 时提供自己的方法,从而覆盖默认实现。

此形式的模板为:

impl<P1..=Pn> ForeignTrait<T1..=Tn> for T0

Enter fullscreen mode Exit fullscreen mode

  • P1..=PnT1..=T0 指代若干参数

仅当满足以下全部条件时,此形式才被允许:

  • T1..=Tn 中至少有一个是本地类型
  • 在第一个本地类型之前,任何 T(其中 TP1..=Pn 中的泛型类型之一)都不得出现
  • 泛型参数 P 可以出现在 T0..Ti 中,只要它被某种中间类型包裹
    • T 作为另一类型的类型参数出现(如 Vec<T>),则认为 T 被包裹
    • T 单独出现,或仅位于基础类型(如 &T)之后,则认为未被包裹

简单示例:

impl From<MyType> for Vec<i32>

Enter fullscreen mode Exit fullscreen mode

这为外部类型 Vec<i32> 实现了外部 trait From<MyType>

以下是一些更复杂的示例,你可以使用上述规则理解它们:

实现 有效?
impl<T> From<T> for MyType OK
impl<T> From<T> for MyType<T> OK
impl<T> From<MyType> for Vec<T> OK
impl<T> ForeignTrait<MyType, T> for Vec<T> OK
-------------------------------------------- ------------
impl<T> ForeignTrait for T Not OK
impl<T> From<T> for T Not OK
impl<T> From<Vec<T>> for T Not OK
impl<T> From<MyType<T>> for T Not OK
impl<T> From<T> for Vec<T> Not OK
impl<T> ForeignTrait<T, MyType> for Vec<T> Not OK

覆盖实现是否属于破坏性变更取决于具体情况:

  • 向现有 trait 添加新实现,且至少有一个新本地类型满足上述条件,则是非破坏性变更
  • 为现有 trait 添加不满足上述条件的实现,则是破坏性变更

注意:

  • impl<T> ForeignTrait<MyType, T> for Vec<T> 是有效的
  • impl<T> ForeignTrait<T, MyType> for Vec<T> 是无效的