实现

语法
实现 :
   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 traits 要求 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 T0,一个 impl 只有在至少满足以下条件之一时才有效

  • Trait 是一个 本地 trait
  • 全部满足以下条件:
    • 类型 T0..=Tn 中至少有一个必须是 本地类型。设 Ti 为第一个这样的类型。
    • T0..Ti (不包括 Ti)中,不得出现任何未覆盖类型参数 P1..=Pn

仅限制未覆盖类型参数的出现。

请注意,出于一致性的目的,基本类型是特殊的。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 检查属性