summaryrefslogtreecommitdiffstats
path: root/src/doc/reference/src/items/associated-items.md
diff options
context:
space:
mode:
Diffstat (limited to 'src/doc/reference/src/items/associated-items.md')
-rw-r--r--src/doc/reference/src/items/associated-items.md145
1 files changed, 140 insertions, 5 deletions
diff --git a/src/doc/reference/src/items/associated-items.md b/src/doc/reference/src/items/associated-items.md
index f5dc31aae..2401127b5 100644
--- a/src/doc/reference/src/items/associated-items.md
+++ b/src/doc/reference/src/items/associated-items.md
@@ -205,22 +205,49 @@ types cannot be defined in [inherent implementations] nor can they be given a
default implementation in traits.
An *associated type declaration* declares a signature for associated type
-definitions. It is written as `type`, then an [identifier], and
-finally an optional list of trait bounds.
+definitions. It is written in one of the following forms, where `Assoc` is the
+name of the associated type, `Params` is a comma-separated list of type,
+lifetime or const parameters, `Bounds` is a plus-separated list of trait bounds
+that the associated type must meet, and `WhereBounds` is a comma-separated list
+of bounds that the parameters must meet:
+
+<!-- ignore: illustrative example forms -->
+```rust,ignore
+type Assoc;
+type Assoc: Bounds;
+type Assoc<Params>;
+type Assoc<Params>: Bounds;
+type Assoc<Params> where WhereBounds;
+type Assoc<Params>: Bounds where WhereBounds;
+```
The identifier is the name of the declared type alias. The optional trait bounds
must be fulfilled by the implementations of the type alias.
There is an implicit [`Sized`] bound on associated types that can be relaxed using the special `?Sized` bound.
-An *associated type definition* defines a type alias on another type. It is
-written as `type`, then an [identifier], then an `=`, and finally a [type].
+An *associated type definition* defines a type alias for the implementation
+of a trait on a type. They are written similarly to an *associated type declaration*,
+but cannot contain `Bounds`, but instead must contain a `Type`:
+
+<!-- ignore: illustrative example forms -->
+```rust,ignore
+type Assoc = Type;
+type Assoc<Params> = Type; // the type `Type` here may reference `Params`
+type Assoc<Params> = Type where WhereBounds;
+type Assoc<Params> where WhereBounds = Type; // deprecated, prefer the form above
+```
If a type `Item` has an associated type `Assoc` from a trait `Trait`, then
`<Item as Trait>::Assoc` is a type that is an alias of the type specified in the
associated type definition. Furthermore, if `Item` is a type parameter, then
`Item::Assoc` can be used in type parameters.
-Associated types must not include [generic parameters] or [where clauses].
+Associated types may include [generic parameters] and [where clauses]; these are
+often referred to as *generic associated types*, or *GATs*. If the type `Thing`
+has an associated type `Item` from a trait `Trait` with the generics `<'a>` , the
+type can be named like `<Thing as Trait>::Item<'x>`, where `'x` is some lifetime
+in scope. In this case, `'x` will be used wherever `'a` appears in the associated
+type definitions on impls.
```rust
trait AssociatedType {
@@ -249,6 +276,37 @@ fn main() {
}
```
+An example of associated types with generics and where clauses:
+
+```rust
+struct ArrayLender<'a, T>(&'a mut [T; 16]);
+
+trait Lend {
+ // Generic associated type declaration
+ type Lender<'a> where Self: 'a;
+ fn lend<'a>(&'a mut self) -> Self::Lender<'a>;
+}
+
+impl<T> Lend for [T; 16] {
+ // Generic associated type definition
+ type Lender<'a> = ArrayLender<'a, T> where Self: 'a;
+
+ fn lend<'a>(&'a mut self) -> Self::Lender<'a> {
+ ArrayLender(self)
+ }
+}
+
+fn borrow<'a, T: Lend>(array: &'a mut T) -> <T as Lend>::Lender<'a> {
+ array.lend()
+}
+
+
+fn main() {
+ let mut array = [0usize; 16];
+ let lender = borrow(&mut array);
+}
+```
+
### Associated Types Container Example
Consider the following example of a `Container` trait. Notice that the type is
@@ -279,6 +337,83 @@ impl<T> Container for Vec<T> {
}
```
+### Relationship between `Bounds` and `WhereBounds`
+
+In this example:
+
+```rust
+# use std::fmt::Debug;
+trait Example {
+ type Output<T>: Ord where T: Debug;
+}
+```
+
+Given a reference to the associated type like `<X as Example>::Output<Y>`, the associated type itself must be `Ord`, and the type `Y` must be `Debug`.
+
+### Required where clauses on generic associated types
+
+Generic associated type declarations on traits currently may require a list of
+where clauses, dependent on functions in the trait and how the GAT is used. These
+rules may be loosened in the future; updates can be found [on the generic
+associated types initiative repository](https://rust-lang.github.io/generic-associated-types-initiative/explainer/required_bounds.html).
+
+In a few words, these where clauses are required in order to maximize the allowed
+definitions of the associated type in impls. To do this, any clauses that *can be
+proven to hold* on functions (using the parameters of the function or trait)
+where a GAT appears as an input or output must also be written on the GAT itself.
+
+```rust
+trait LendingIterator {
+ type Item<'x> where Self: 'x;
+ fn next<'a>(&'a mut self) -> Self::Item<'a>;
+}
+```
+
+In the above, on the `next` function, we can prove that `Self: 'a`, because of
+the implied bounds from `&'a mut self`; therefore, we must write the equivalent
+bound on the GAT itself: `where Self: 'x`.
+
+When there are multiple functions in a trait that use the GAT, then the
+*intersection* of the bounds from the different functions are used, rather than
+the union.
+
+```rust
+trait Check<T> {
+ type Checker<'x>;
+ fn create_checker<'a>(item: &'a T) -> Self::Checker<'a>;
+ fn do_check(checker: Self::Checker<'_>);
+}
+```
+
+In this example, no bounds are required on the `type Checker<'a>;`. While we
+know that `T: 'a` on `create_checker`, we do not know that on `do_check`. However,
+if `do_check` was commented out, then the `where T: 'x` bound would be required
+on `Checker`.
+
+The bounds on associated types also propagate required where clauses.
+
+```rust
+trait Iterable {
+ type Item<'a> where Self: 'a;
+ type Iterator<'a>: Iterator<Item = Self::Item<'a>> where Self: 'a;
+ fn iter<'a>(&'a self) -> Self::Iterator<'a>;
+}
+```
+
+Here, `where Self: 'a` is required on `Item` because of `iter`. However, `Item`
+is used in the bounds of `Iterator`, the `where Self: 'a` clause is also required
+there.
+
+Finally, any explicit uses of `'static` on GATs in the trait do not count towards
+the required bounds.
+
+```rust
+trait StaticReturn {
+ type Y<'a>;
+ fn foo(&self) -> Self::Y<'static>;
+}
+```
+
## Associated Constants
*Associated constants* are [constants] associated with a type.