1.17.1. Coherence
Coherence means that for a given type and method, there is only one correct choice for the implementation of that method on that type.
The orphan rule means that as long as either the trait or the type is in the local crate, you can implement that trait for that type. For example:
- A type you define locally can implement the
Debugtrait - You can implement a trait you define locally for
bool - You cannot implement
Debugforbool, because neither side is local
There are exceptions to the orphan rule, which we will discuss below.
1.17.2. Blanket Implementation
A blanket implementation, also called a general implementation, means that Rust allows a default implementation for every type that satisfies a trait bound.
Its template is:
impl<T> MyTrait for T where T: ...
This means implementing MyTrait for all types that implement some trait.
For example:
impl<T: Display> ToString for T {}
This means implementing ToString for all types that implement Display.
This example is not yet written in template form. In template form, it would be:
impl<T> ToString for T where T: Display {}
Note that only the crate that defines the trait is allowed to use blanket implementations. Adding a blanket implementation to an existing trait is a breaking change.
1.17.3. Fundamental Types
Some types are so fundamental that we need to allow anyone to implement traits for them, even if that would violate the orphan rule. These types are marked #[fundamental], and currently include &T, &mut T, Box<T>, and Pin<P>.
- One extra note: the main purpose of
Pin<P>is to ensure that a value cannot be moved, that is, to prevent operations such asstd::mem::replace,std::mem::swap, orstd::mem::takefrom changing the value’s physical address - For the purpose of the orphan rule, these types are actually erased before orphan-rule checking takes place
Note: using blanket implementations on fundamental types is also considered a breaking change.
1.17.4. Covered Implementation
Sometimes you need to implement an external trait for an external type, which is called a covered implementation. This uses one narrow exemption established by the orphan rule: it allows an external trait to be implemented for an external type in very specific cases.
Note: covered implementation can refer either to Covered Implementation or Override Implementation. Here it refers to Covered Implementation. Override implementation means that when a struct implements a trait and provides its own methods, it can override the default implementation.
The template for this form is:
impl<P1..=Pn> ForeignTrait<T1..=Tn> for T0
-
P1..=PnandT1..=T0refer to a number of parameters
This form is allowed only if all of the following conditions are met:
- At least one of
T1..=Tnis a local type - No
T(whereTis one of the generic types inP1..=Pn) may appear before the first such local type - A generic type parameter
Pmay appear inT0..Tias long as it is wrapped by some intermediate type- If
Tappears as a type parameter of another type, such asVec<T>, thenTis considered wrapped - If
Tappears only by itself, or behind a fundamental type such as&T, then it is not wrapped
- If
For a simple example:
impl From<MyType> for Vec<i32>
This implements the external From<MyType> trait for the external Vec<i32> type.
Here are some more complex examples. You can use the rules above to understand them:
| Implementation | Valid? |
|---|---|
impl<T> From<T> for MyType |
OK |
impl<T> From<T> for MyType<T> |
OK |
impl<T> From<MyType> for Vec<T> |
OK |
impl<T> ForeignTrait<MyType, T> for Vec<T> |
OK |
-------------------------------------------- |
------------ |
impl<T> ForeignTrait for T |
Not OK |
impl<T> From<T> for T |
Not OK |
impl<T> From<Vec<T>> for T |
Not OK |
impl<T> From<MyType<T>> for T |
Not OK |
impl<T> From<T> for Vec<T> |
Not OK |
impl<T> ForeignTrait<T, MyType> for Vec<T> |
Not OK |
Whether a covered implementation is a breaking change depends on the specific situation:
- Adding a new implementation to an existing trait, with at least one new local type that satisfies the conditions above, is a non-breaking change
- Adding an implementation for an existing trait that does not meet the conditions above is a breaking change
Note:
-
impl<T> ForeignTrait<MyType, T> for Vec<T>is valid -
impl<T> ForeignTrait<T, MyType> for Vec<T>is invalid