实现

语法

实现 :

   固有实现 | 特征实现

固有实现 :

   impl 泛型参数? 类型 Where子句? {

      内部属性*

      关联项*

   }

特征实现 :

   unsafe? impl 泛型参数? !? 类型路径 for 类型

   Where子句?

   {

      内部属性*

      关联项*

   }

实现 是一个将项目与 实现类型 关联起来的项目。实现使用关键字 impl 定义,并包含属于正在实现的类型的实例或静态类型的函数。

有两种类型的实现

固有实现

固有实现定义为 impl 关键字、泛型类型声明、指向名义类型的路径、where 子句和一组括号内的可关联项目的序列。

名义类型称为 实现类型,可关联项目是实现类型的 关联项目

固有实现将包含的项目与实现类型相关联。固有实现可以包含 关联函数(包括 方法)和 关联常量。它们不能包含关联类型别名。

关联项目的 路径 是指向实现类型的任何路径,后跟关联项目的标识符作为最终路径组件。

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

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();
}

特征实现

特征实现 的定义类似于固有实现,只是可选的泛型类型声明后跟一个 特征,然后是关键字 for,然后是指向名义类型的路径。

该特征称为 已实现特征。实现类型实现了已实现特征。

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

关联项目的路径是 < 后跟指向实现类型的路径,后跟 as,后跟指向特征的路径,后跟 > 作为路径组件,后跟关联项目的路径组件。

不安全特征 要求特征实现以 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,
        }
    }
}
}

特征实现一致性

如果特征实现无法通过孤儿规则检查或存在重叠的实现实例,则该实现被认为是不连贯的。

当满足以下条件时,两个特征实现会发生重叠:实现所针对的特征存在非空交集,并且可以使用相同的类型实例化这些实现。

孤儿规则

给定 impl<P1..=Pn> Trait<T1..=Tn> for T0,仅当满足以下至少一个条件时,impl 才有效:

仅限制_未覆盖_类型参数的出现。请注意,出于一致性目的,基本类型比较特殊。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 */
}
}

如果泛型参数至少在以下一项中出现一次,则该参数会_约束_实现:

  • 已实现的特征(如果有)
  • 实现类型
  • 作为包含另一个约束实现的参数的类型的边界中的关联类型

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

约束情况示例

#![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 检查属性