实现
Syntax
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 的路径,后跟 > 作为路径组件,后跟关联项的路径组件。
不安全的 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 实现重叠。
孤立规则
孤立规则规定,只有当 trait 或实现中的至少一个类型在当前 crate 中定义时,才允许 trait 实现。它防止了跨不同 crate 的冲突 trait 实现,并且是确保一致性的关键。
孤立实现是为外部类型实现外部 trait 的实现。如果自由允许这些,两个 crate 可能以不兼容的方式为同一类型实现相同的 trait,从而导致添加或更新依赖项可能由于冲突的实现而破坏编译的情况。
孤立规则使库作者能够向其 trait 添加新实现,而不必担心它们会破坏下游代码。如果没有这些限制,库就无法添加像 impl<T: Display> MyTrait for T 这样的实现,而不会与下游实现发生潜在冲突。
给定 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 {
/* Treat the integer as a sequence of bits */
}
}
如果参数至少出现在以下位置之一,则泛型参数约束实现:
类型和 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 关键字之前包含外部属性,在包含关联项的括号内包含内部属性。内部属性必须在任何关联项之前。在此处有意义的属性是 cfg、deprecated、doc 和 lint 检查属性。