实现
语法
实现 :
内部实现 | Trait实现内部实现 :
impl
泛型参数组? 类型 Where从句?{
内部属性*
关联条目*
}
Trait实现 :
unsafe
?impl
泛型参数组?!
? 类型路径for
类型
Where从句?
{
内部属性*
关联条目*
}
实现 条目将 实现类型 与其中条目相关联。
实现使用关键字 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() { // 实现类型的真实路径和 impl 在同一模块。 color::Color::WHITE; // 不同模块中的 Impl 块仍然是通过类型的路径来访问。 color::Color::red(); // 也可以将路径重新导出到实现类型。 Color::red(); // 无效,因为在 `values` 中没有使用 pub 。 // values::Color::red(); }
Trait 实现
trait实现 和内部实现类似,只是可选的泛型类型声明后面是 trait ,再跟着 for
关键字,最后是指向具名类型的路径。
该 trait 被称为 实现 trait ,由实现类型实现。
trait 所有非默认关联条目必须实现,可以重新定义其定义的默认关联条目,但无法定义任何其他条目。
与实现类型相关联的关联条目的路径是 <
,后跟到实现类型的路径,然后是 as
,后跟到 trait 的路径,之后 >
作为路径组件,然后是关联条目的路径组件。
Unsafe traits 指的是需要在 trait 实现中使用 unsafe
关键字的 trait 。
#![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 集合存在非空交集,并且这两个 trait 实现都可以实例化为同一类型。
唯一性规则
规定 impl<P1..=Pn> Trait<T1..=Tn> for T0
只有当以下至少一项为真时, impl
才是有效:
Trait
是 局部trait- 全部为
仅出现 未覆盖 类型参数是受限制的。需要注意的是,在一致性的目的下, 基本类型 是特殊的。
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 { /* 将整数视为比特序列 */ } }
如果泛型参数至少在一种类型的关联条目中出现,则该泛型参数 约束 了实现:
类型和常量参数必须始终约束实现。如果在关联类型中使用生命周期,则生命周期必须约束实现。
约束示例:
#![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 通过作为 GenericTrait 的一个参数来约束。 impl<T> GenericTrait<T> for i32 { /* ... */ } // T 通过作为 GenericTrait 的一个参数来约束。 impl<T> Trait for GenericStruct<T> { /* ... */ } // 同样地, N 通过作为 ConstGenericStruct 的一个参数来约束 impl<const N: usize> Trait for ConstGenericStruct<N> { /* ... */ } // T 通过在类型 `U` 的约束中的关联类型来约束,该类型本身是约束 trait 的一个泛型参数。 impl<T, U> GenericTrait<U> for u32 where U: HasAssocType<Ty = T> { /* ... */ } // 和前面一样,除了类型是 `(U, isize)` 。 `U` 出现在包括 `T` 的类型里面,而不是类型本身。 impl<T, U> GenericStruct<U> where (U, isize): HasAssocType<Ty = T> { /* ... */ } }
非约束性的示例:
#![allow(unused)] fn main() { // 其余的都是错误,因为它们的类型或常量参数不受约束。 // T没有约束,因为它根本就没有出现。 impl<T> Struct { /* ... */ } // 由于同样的原因,N并没有受到约束。 impl<const N: usize> Struct { /* ... */ } // 在实现中使用 T 并不会约束 impl。 impl<T> Struct { fn uses_t(t: &T) { /* ... */ } } // 在 U 的绑定中, T 用作关联类型,但 U 没有约束。 impl<T, U> Struct where U: HasAssocType<Ty = T> { /* ... */ } // T 在绑定中使用,但不是作为一个关联类型,所以它不受约束。 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
关键字之前包含外围 属性 ,在包含关联条目的括号内部包含内部 属性 。
内部属性必须在任何关联条目之前。在这里有意义的属性是 cfg
, deprecated
, doc
和 代码分析 。