Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

1.17 孤儿规则与连贯性(一致性):泛实现(Blanket Implementation)、覆盖实现(Covered Implementation)

1.17.1. 连贯性(一致性)属性

连贯性(或者叫一致性)是指对于给定的类型和方法,只会有一个正确的选择,用于该方法对该类型的实现

孤儿规则(orphan rule)指的是只要trait或者类型在本地的crate,那就可以为该类型实现该trait。 比如说:

  • 你定义在本地的类型可以实现Debug trait
  • 可以为bool类型实现你定义在本地的trait
  • 不能为bool类型实现Debug trait,因为这两者都不是定义在本地的

这个孤儿规则也有例外,我们下文再讲。

1.17.2. 泛实现(Blanket Implementation)

泛实现(Blanket Implementation),又叫通用实现,它指的是Rust允许为所有符合某个trait约束的类型提供默认实现。

它的模版是:

#![allow(unused)]
fn main() {
impl<T> MyTrait for T where T:
}

它的意思是为所有实现了某个trait的类型实现MyTrait

例如:

#![allow(unused)]
fn main() {
impl<T: Display> ToString for T {}
}

这句话的意思是为所有实现了Display trait的类型实现了ToString trait。

这个例子的写法还不是模版的写法,换成模版的写法就是:

#![allow(unused)]
fn main() {
impl<T> ToString for T where T: Display {}
}

需要注意的是,只有定义trait的crate允许使用泛实现。添加泛实现到现有trait属于破坏性变化。

1.17.3. 基础类型

有些类型太过于基础了,需要允许任何人在它们上实现trait(即使违反孤儿规则)。这些类型被标记为#[fundamental],目前包括&T&mut TBox<T>Pin<P>

  • 一点补充:Pin<P>的主要作用是确保某个值无法被移动,即防止Rust代码调用 std::mem::replacestd::mem::swap或者std::mem::take之类的操作导致值的物理地址发生变化
  • 处于孤儿原则的目的,实际上在孤儿规则检查之前,它们会被抹除

注意:对于基础类型使用泛实现也被认为是破坏性变化

1.17.4. 覆盖实现(Covered Implementation)

有时候需要为外部类型实现外部trait,这就叫覆盖实现(Covered Implementation)。这样写使用到了孤儿规则制定的一个狭窄的豁免:允许在非常特定的情况下为外来类型实现外部trait。

注意:覆盖实现既可以指Covered Implementation,也可以指Override Implementation(又叫覆写实现),这里指的是Covered Implementation。覆写实现指的是当结构体实现 trait并提供自己的方法时,可以**覆写(Override)**默认实现。

这种写法的模版是:

#![allow(unused)]
fn main() {
impl<P1..=Pn> ForeignTriat<T1..=Tn> for T0
}
  • P1..=PnT1..=T0指的是若干个参数

这种写法只在以下条件被允许:

  • T1..=Tn里至少有一个是本地类型
  • 没有T(T是指泛型类型P1..=Pn中的一个)在第一个这样的本地类型之前
  • 泛型类型参数P允许出现在T0..Ti,只要它们被某种中间(intermediate)类型所包裹
    • 如果T作为其他类型(例如Vec<T>)的类型参数出现,那就说明T被包裹了
    • T只作为本身,或者位于基础类型后(例如&T),就不是包裹

举个简单的例子,比如说:

#![allow(unused)]
fn main() {
impl From<MyType> for Vec<i32>
}

需要为外部的Vec<i32>这个类型来实现From<MyType>这个trait

再举一些复杂的例子,你可以对照着规则来理解:

实现是否可行
impl<T> From<T> for MyTypeOK
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 TNot OK
impl<T> From<T> for TNot OK
impl<T> From<Vec<T>> for TNot OK
impl<T> From<MyType<T>> for TNot 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>是非法的