1.17 孤儿规则与连贯性(一致性):泛实现(Blanket Implementation)、覆盖实现(Covered Implementation)
1.17.1. 连贯性(一致性)属性
连贯性(或者叫一致性)是指对于给定的类型和方法,只会有一个正确的选择,用于该方法对该类型的实现。
孤儿规则(orphan rule)指的是只要trait或者类型在本地的crate,那就可以为该类型实现该trait。比如说:
- 你定义在本地的类型可以实现Debugtrait
- 可以为bool类型实现你定义在本地的trait
- 不能为bool类型实现Debugtrait,因为这两者都不是定义在本地的
这个孤儿规则也有例外,我们下文再讲。
1.17.2. 泛实现(Blanket Implementation)
泛实现(Blanket Implementation),又叫通用实现,它指的是Rust允许为所有符合某个trait约束的类型提供默认实现。
它的模版是:
impl<T> MyTrait for T where T:它的意思是为所有实现了某个trait的类型实现MyTrait。
例如:
impl<T: Display> ToString for T {}这句话的意思是为所有实现了Displaytrait的类型实现了ToStringtrait。
这个例子的写法还不是模版的写法,换成模版的写法就是:
impl<T> ToString for T where T: Display {}需要注意的是,只有定义trait的crate允许使用泛实现。添加泛实现到现有trait属于破坏性变化。
1.17.3. 基础类型
有些类型太过于基础了,需要允许任何人在它们上实现trait(即使违反孤儿规则)。这些类型被标记为#[fundamental],目前包括&T、&mut T、Box<T>、Pin<P>。
- 一点补充:Pin<P>的主要作用是确保某个值无法被移动,即防止Rust代码调用std::mem::replace、std::mem::swap或者std::mem::take之类的操作导致值的物理地址发生变化
- 处于孤儿原则的目的,实际上在孤儿规则检查之前,它们会被抹除
注意:对于基础类型使用泛实现也被认为是破坏性变化。
1.17.4. 覆盖实现(Covered Implementation)
有时候需要为外部类型实现外部trait,这就叫覆盖实现(Covered Implementation)。这样写使用到了孤儿规则制定的一个狭窄的豁免:允许在非常特定的情况下为外来类型实现外部trait。
注意:覆盖实现既可以指Covered Implementation,也可以指Override Implementation(又叫覆写实现),这里指的是Covered Implementation。覆写实现指的是当结构体实现 trait并提供自己的方法时,可以覆写(Override)默认实现。
这种写法的模版是:
impl<P1..=Pn> ForeignTriat<T1..=Tn> for T0P1..=Pn和T1..=T0指的是若干个参数
这种写法只在以下条件被允许:
-T1..=Tn里至少有一个是本地类型
- 没有T(T是指泛型类型P1..=Pn中的一个)在第一个这样的本地类型之前
- 泛型类型参数P允许出现在T0..Ti,只要它们被某种中间(intermediate)类型所包裹
- 如果T作为其他类型(例如Vec<T>)的类型参数出现,那就说明T被包裹了
-T只作为本身,或者位于基础类型后(例如&T),就不是包裹
举个简单的例子,比如说:
impl From<MyType> for Vec<i32>需要为外部的Vec<i32>这个类型来实现From<MyType>这个trait
再举一些复杂的例子,你可以对照着规则来理解:
| 实现 | 是否可行 |
|---|---|
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>是非法的