实现

语法
Implementation :
   InherentImpl | TraitImpl

InherentImpl :
   impl GenericParams? Type WhereClause? {
      InnerAttribute*
      AssociatedItem*
   }

TraitImpl :
   unsafe? impl GenericParams? !? TypePath for Type
   WhereClause?
   {
      InnerAttribute*
      AssociatedItem*
   }

一个实现是关联项与一个实现类型的项。实现使用关键字impl定义,并包含属于正在被实现的类型的实例的函数,或者属于该类型本身(静态)。

实现有两种类型:

  • 固有实现
  • trait 实现

固有实现

固有实现定义为以下序列:impl关键字、泛型类型声明、指向标称类型的路径、where 子句,以及一对花括号包含的可关联项集合。

该标称类型称为实现类型,可关联项称为该实现类型的关联项

固有实现将包含的项关联到实现类型。

固有实现可以包含关联函数(包括方法)和关联常量

它们不能包含关联类型别名。

指向关联项的路径可以是任何指向实现类型的路径,后接该关联项的标识符作为最后一个路径组件。

一个类型可以有多个固有实现。实现类型必须与原始类型定义在同一个 crate 中定义。

pub mod color {
    pub struct Color(pub u8, pub u8, pub u8);

    impl Color {
        pub const WHITE: Color = Color(255, 255, 255);
    }
}

mod values {
    use super::color::Color;
    impl Color {
        pub fn red() -> Color {
            Color(255, 0, 0)
        }
    }
}

pub use self::color::Color;
fn main() {
    // Actual path to the implementing type and impl in the same module.
    color::Color::WHITE;

    // Impl blocks in different modules are still accessed through a path to the type.
    color::Color::red();

    // Re-exported paths to the implementing type also work.
    Color::red();

    // Does not work, because use in `values` is not pub.
    // values::Color::red();
}

Trait 实现

一个trait 实现的定义类似于固有实现,不同之处在于可选的泛型类型声明后接一个trait,然后是关键字for,再后接指向一个标称类型的路径。

该 trait 称为已实现的 trait。实现类型实现了该已实现的 trait。

trait 实现必须定义已实现的 trait 声明的所有非默认关联项,可以重新定义已实现的 trait 定义的默认关联项,并且不能定义任何其他项。

关联项的路径是<,后接实现类型的路径,后接as,后接 trait 的路径,再后接>作为一个路径组件,最后后接关联项的路径组件。

Unsafe trait 要求 trait 实现以关键字unsafe开头。

#![allow(unused)]
fn main() {
#[derive(Copy, Clone)]
struct Point {x: f64, y: f64};
type Surface = i32;
struct BoundingBox {x: f64, y: f64, width: f64, height: f64};
trait Shape { fn draw(&self, s: Surface); fn bounding_box(&self) -> BoundingBox; }
fn do_draw_circle(s: Surface, c: Circle) { }
struct Circle {
    radius: f64,
    center: Point,
}

impl Copy for Circle {}

impl Clone for Circle {
    fn clone(&self) -> Circle { *self }
}

impl Shape for Circle {
    fn draw(&self, s: Surface) { do_draw_circle(s, *self); }
    fn bounding_box(&self) -> BoundingBox {
        let r = self.radius;
        BoundingBox {
            x: self.center.x - r,
            y: self.center.y - r,
            width: 2.0 * r,
            height: 2.0 * r,
        }
    }
}
}

Trait 实现一致性

如果孤儿规则检查失败或存在重叠的实现实例,则 trait 实现被认为是不一致的。

当两个 trait 实现所针对的 trait 存在非空交集,并且可以用相同的类型进行实例化时,它们就重叠了。

孤儿规则

对于给定的impl<P1..=Pn> Trait<T1..=Tn> for T0impl只有在以下至少一个条件为真时才有效:

  • Trait本地 trait
  • 所有以下条件为真:
    • 类型T0..=Tn中至少有一个必须是本地类型。令Ti为第一个这样的类型。
    • 没有未覆盖类型参数P1..=Pn可能出现在T0..Ti中(不包括Ti)。

只有未覆盖类型参数的出现受到限制。

注意,为了实现一致性,基础类型构造器是特殊的。Box<T>中的T不被认为是覆盖的,而Box<LocalType>被认为是本地类型。

泛型实现

实现可以接受泛型参数,这些参数可以在实现的其他部分使用。实现参数直接写在impl关键字之后。

#![allow(unused)]
fn main() {
trait Seq<T> { fn dummy(&self, _: T) { } }
impl<T> Seq<T> for Vec<T> {
    /* ... */
}
impl Seq<bool> for u32 {
    /* Treat the integer as a sequence of bits */
}
}

如果泛型参数至少在以下之一中出现一次,则它约束一个实现:

  • 已实现的 trait(如果存在)
  • 实现类型
  • 作为包含另一个约束实现的参数的类型的约束中的关联类型

类型参数和 const 参数必须始终约束实现。如果生命周期在关联类型中使用,则必须约束实现。

约束情况的示例

#![allow(unused)]
fn main() {
trait Trait{}
trait GenericTrait<T> {}
trait HasAssocType { type Ty; }
struct Struct;
struct GenericStruct<T>(T);
struct ConstGenericStruct<const N: usize>([(); N]);
// T constrains by being an argument to GenericTrait.
impl<T> GenericTrait<T> for i32 { /* ... */ }

// T constrains by being an argument to GenericStruct
impl<T> Trait for GenericStruct<T> { /* ... */ }

// Likewise, N constrains by being an argument to ConstGenericStruct
impl<const N: usize> Trait for ConstGenericStruct<N> { /* ... */ }

// T constrains by being in an associated type in a bound for type `U` which is
// itself a generic parameter constraining the trait.
impl<T, U> GenericTrait<U> for u32 where U: HasAssocType<Ty = T> { /* ... */ }

// Like previous, except the type is `(U, isize)`. `U` appears inside the type
// that includes `T`, and is not the type itself.
impl<T, U> GenericStruct<U> where (U, isize): HasAssocType<Ty = T> { /* ... */ }
}

非约束情况的示例

#![allow(unused)]
fn main() {
// The rest of these are errors, since they have type or const parameters that
// do not constrain.

// T does not constrain since it does not appear at all.
impl<T> Struct { /* ... */ }

// N does not constrain for the same reason.
impl<const N: usize> Struct { /* ... */ }

// Usage of T inside the implementation does not constrain the impl.
impl<T> Struct {
    fn uses_t(t: &T) { /* ... */ }
}

// T is used as an associated type in the bounds for U, but U does not constrain.
impl<T, U> Struct where U: HasAssocType<Ty = T> { /* ... */ }

// T is used in the bounds, but not as an associated type, so it does not constrain.
impl<T, U> GenericTrait<U> for u32 where U: GenericTrait<T> {}
}

允许的非约束生命周期参数示例

#![allow(unused)]
fn main() {
struct Struct;
impl<'a> Struct {}
}

不允许的非约束生命周期参数示例

#![allow(unused)]
fn main() {
struct Struct;
trait HasAssocType { type Ty; }
impl<'a> HasAssocType for Struct {
    type Ty = &'a Struct;
}
}

实现上的属性

实现可以在impl关键字之前包含外部属性,以及在包含关联项的方括号内部包含内部属性。内部属性必须出现在任何关联项之前。在此处有意义的属性包括cfgdeprecateddoclint 检查属性