Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit ffd1096

Browse files
committedMar 17, 2018
More docs for generic parameters and trait bounds
1 parent f6d6871 commit ffd1096

File tree

3 files changed

+245
-40
lines changed

3 files changed

+245
-40
lines changed
 

Diff for: ‎src/items/generics.md

+104-16
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,106 @@
1-
# Type Parameters
1+
# Type and Lifetime Parameters
2+
3+
> **<sup>Syntax</sup>**
4+
> _Generics_ :
5+
> &nbsp;&nbsp; `<` _GenericParams_ `>`
6+
>
7+
> _GenericParams_ :
8+
> &nbsp;&nbsp; &nbsp;&nbsp; _LifetimeParams_
9+
> &nbsp;&nbsp; | ( _LifetimeParam_ `,` )<sup>\*</sup> _TypeParams_
10+
>
11+
> _LifetimeParams_ :
12+
> &nbsp;&nbsp; ( _LifetimeParam_ `,` )<sup>\*</sup> _LifetimeParam_<sup>?</sup>
13+
>
14+
> _LifetimeParam_ :
15+
> &nbsp;&nbsp; [LIFETIME_OR_LABEL] `:` [_LifetimeBounds_]<sup>?</sup>
16+
>
17+
> _TypeParams_:
18+
> &nbsp;&nbsp; ( _TypeParam_ `,` )<sup>\*</sup> _TypeParam_ <sup>?</sup>
19+
>
20+
> _TypeParam_ :
21+
> &nbsp;&nbsp; [IDENTIFIER] ( `:` [_TypeParamBounds_] )<sup>?</sup> ( `=` [_Type_] )<sup>?</sup>
222
323
Functions, type aliases, structs, enumerations, unions, traits and
4-
implementations may be *parameterized* by type. Type parameters are given as a
5-
comma-separated list of identifiers enclosed in angle brackets (`<...>`), after
6-
the name of the item (except for implementations, where they come directly
7-
after `impl`) and before its definition.
8-
9-
The type parameters of an item are considered "part of the name", not part of
10-
the type of the item. A referencing [path] must (in principle) provide type
11-
arguments as a list of comma-separated types enclosed within angle brackets, in
12-
order to refer to the type-parameterized item. In practice, the type-inference
13-
system can usually infer such argument types from context. There are no general
14-
type-parametric types, only type-parametric items. That is, Rust has no notion
15-
of type abstraction: there are no higher-ranked (or "forall") types abstracted
16-
over other types, though higher-ranked types do exist for lifetimes.
17-
18-
[path]: paths.html
24+
implementations may be *parameterized* by types and lifetimes. These parameters
25+
are listed in angle <span class="parenthetical">brackets (`<...>`)</span>,
26+
usually immediattely after and before its definition the name of the item. For
27+
implementations, which don't have a name, they come directly after `impl`.
28+
Lifetime parameters must be declared before type parameters. Some examples of
29+
items with type and lifetime parameters:
30+
31+
```rust
32+
fn foo<'a, T>() {}
33+
trait A<U> {}
34+
struct Ref<'a, T> where T: 'a { r: &'a T }
35+
```
36+
37+
[References], [raw pointers], [arrays], [slices][arrays], [tuples] and
38+
[function pointers] have lifetime or type parameters as well, but are not
39+
refered to with path syntax.
40+
41+
## Where clauses
42+
43+
> **<sup>Syntax</sup>**
44+
> _WhereClause_ :
45+
> &nbsp;&nbsp; `where` ( _WhereClauseItem_ `,` )<sup>\*</sup> _WhereClauseItem_ <sup>?</sup>
46+
>
47+
> _WhereClauseItem_ :
48+
> &nbsp;&nbsp; &nbsp;&nbsp; _LifetimeWhereClauseItem_
49+
> &nbsp;&nbsp; | _TypeBoundWhereClauseItem_
50+
>
51+
> _LifetimeWhereClauseItem_ :
52+
> &nbsp;&nbsp; [_Lifetime_] `:` [_LifetimeBounds_]
53+
>
54+
> _TypeBoundWhereClauseItem_ :
55+
> &nbsp;&nbsp; _ForLifetimes_<sup>?</sup> [_Type_] `:` [_TypeParamBounds_]<sup>?</sup>
56+
>
57+
> _ForLifetimes_ :
58+
> &nbsp;&nbsp; `for` `<` [_LifetimeParams_](#type-and-lifetime-parameters) `>`
59+
60+
*Where clauses* provide an another way to specify bounds on type and lifetime
61+
parameters as well as a way to specify bounds on types that aren't type
62+
parameters.
63+
64+
Bounds that don't use the item's parameters are checked when the item is
65+
defined. It is an error for such a bound to be false.
66+
67+
[`Copy`], [`Clone`] and [`Sized`] bounds are also checked for certain generic
68+
types when defining the item. It is an error to have `Copy` or `Clone`as a
69+
bound on a mutable reference, [trait object] or [slice][arrays] or `Sized` as a
70+
bound on a trait object or slice.
71+
72+
```rust,ignore
73+
struct A<T>
74+
where
75+
T: Iterator, // Could use A<T: Iterator> instead
76+
T::Item: Copy,
77+
String: PartialEq<T>,
78+
i32: Default, // Allowed, but not useful
79+
i32: Iterator, // Error: the trait bound is not satisfied
80+
[T]: Copy, // Error: the trait bound is not satisfied
81+
{
82+
f: T,
83+
}
84+
```
85+
86+
[IDENTIFIER]: identifiers.html
87+
[LIFETIME_OR_LABEL]: tokens.html#lifetimes-and-loop-labels
88+
89+
[_LifetimeBounds_]: trait-bounds.html
90+
[_Lifetime_]: trait-bounds.html
91+
[_Type_]: types.html
92+
[_TypeParamBounds_]: trait-bounds.html
93+
94+
[arrays]: types.html#array-and-slice-types
95+
[function pointers]: types.html#function-pointer-types
96+
[references]: types.html#shared-references-
97+
[raw pointers]: types.html#raw-pointers-const-and-mut
98+
[`Clone`]: special-types-and-traits.html#clone
99+
[`Copy`]: special-types-and-traits.html#copy
100+
[`Sized`]: special-types-and-traits.html#sized
101+
[tuples]: types.html#tuple-types
102+
[trait object]: types.html#trait-objects
103+
104+
[path]: ../paths.html
105+
[Trait]: traits.html#trait-bounds
106+
[_TypePath_]: paths.html

Diff for: ‎src/trait-bounds.md

+137-17
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,148 @@
1-
# Trait bounds
1+
# Trait and lifetime bounds
22

3-
Generic functions may use traits as _bounds_ on their type parameters. This
4-
will have three effects:
3+
> **<sup>Syntax</sup>**
4+
> _TypeParamBounds_ :
5+
> &nbsp;&nbsp; _TypeParamBound_ ( `+` _TypeParamBound_ )<sup>\*</sup> `+`<sup>?</sup>
6+
>
7+
> _TypeParamBound_ :
8+
> &nbsp;&nbsp; &nbsp;&nbsp; _Lifetime_ | _TraitBound_
9+
>
10+
> _TraitBound_ :
11+
> &nbsp;&nbsp; &nbsp;&nbsp; `?`<sup>?</sup>
12+
> [_ForLifetimes_](#higher-ranked-trait-bounds)<sup>?</sup> [_TraitPath_]
13+
> &nbsp;&nbsp; | `(` `?`<sup>?</sup>
14+
> [_ForLifetimes_](#higher-ranked-trait-bounds)<sup>?</sup> [_TraitPath_] `)`
15+
>
16+
> _LifetimeBounds_ :
17+
> &nbsp;&nbsp; ( _Lifetime_ `+` )<sup>\*</sup> _Lifetime_<sup>?</sup>
18+
>
19+
> _Lifetime_ :
20+
> &nbsp;&nbsp; &nbsp;&nbsp; [LIFETIME_OR_LABEL]
21+
> &nbsp;&nbsp; | `'static`
522
6-
- Only types that have the trait may instantiate the parameter.
7-
- Within the generic function, the methods of the trait can be called on values
8-
that have the parameter's type. Associated types can be used in the
9-
function's signature, and associated constants can be used in expressions
10-
within the function body.
11-
- Generic functions and types with the same or weaker bounds can use the
12-
generic type in the function body or signature.
23+
[Trait] and lifetime bounds provide a way for [generic items][generic] to
24+
restrict which types and lifetimes are used as their parameters. Bounds can be
25+
provided on any type in a [where clause]. There are also shorter forms for
26+
certain common cases:
1327

14-
For example:
28+
* Bounds written after declaring a [generic parameter][generic]:
29+
`fn f<A: Copy>() {}` is the same as `fn f<A> where A: Copy () {}`.
30+
* In trait declarations as [supertraits]: `trait Circle : Shape {}` is
31+
equivalent to `trait Circle where Self : Shape {}`.
32+
* In trait declarations as bounds on [associated types]:
33+
`trait A { type B: Copy; }` is equivalent to
34+
`trait A where Self::B: Copy { type B; }`.
35+
36+
Bounds on an item must be satisfied when using the item. When type checking and
37+
borrow checking a generic item, the bounds can be used to determine that a
38+
trait is implemented for a type. For example, given `Ty: Trait`
39+
40+
* In the body of a generic function, methods from `Trait` can be called on `Ty`
41+
values. Likewise associated constants on the `Trait` can be used.
42+
* Associated types from `Trait` can be used.
43+
* Generic functions and types with a `T: Trait` bounds can be used with `Ty`
44+
being used for `T`.
1545

1646
```rust
1747
# type Surface = i32;
18-
# trait Shape { fn draw(&self, Surface); }
19-
struct Figure<S: Shape>(S, S);
48+
trait Shape {
49+
fn draw(&self, Surface);
50+
fn name() -> &'static str;
51+
}
52+
2053
fn draw_twice<T: Shape>(surface: Surface, sh: T) {
54+
sh.draw(surface); // Can call method because T: Shape
2155
sh.draw(surface);
22-
sh.draw(surface);
2356
}
24-
fn draw_figure<U: Shape>(surface: Surface, Figure(sh1, sh2): Figure<U>) {
25-
sh1.draw(surface);
26-
draw_twice(surface, sh2); // Can call this since U: Shape
57+
58+
fn copy_and_draw_twice<T: Copy>(surface: Surface, sh: T) where T: Shape {
59+
let shape_copy = sh; // doesn't move sh because T: Copy
60+
draw_twice(surface, sh); // Can use generic function because T: Shape
61+
}
62+
63+
struct Figure<S: Shape>(S, S);
64+
65+
fn name_figure<U: Shape>(
66+
figure: Figure<U>, // Type Figure<U> is well-formed because U: Shape
67+
) {
68+
println!(
69+
"Figure of two {}",
70+
U::name(), // Can use associated function
71+
);
72+
}
73+
```
74+
75+
Trait and lifetime bounds are also used to name [trait objects].
76+
77+
## `?Sized`
78+
79+
`?` is only used to declare that the [`Sized`] trait may not be
80+
implemented for a type parameter or associated type. `?Sized` may
81+
not be used as a bound for other types.
82+
83+
## Lifetime bounds
84+
85+
Lifetime bounds can be applied to types or other lifetimes. The bound `'a: 'b`
86+
is usually read as `'a` *outlives* `'b`. `'a: 'b` means that `'a` lasts longer
87+
than `'b`, so a reference `&'a ()` is valid whenever `&'b ()` is valid.
88+
89+
```rust
90+
fn f<'a, 'b>(x: &'a i32, mut y: &'b i32) where 'a: 'b {
91+
y = x; // &'a i32 is a subtype of &'b i32 because 'a: 'b
92+
let r: &'b &'a i32 = &&0; // &'b &'a i32 is well formed because 'a: 'b
93+
}
94+
```
95+
96+
`T: 'a` means that all lifetime parameters of `T` outlive `'a`. For example if
97+
`'a` is an unconstrained lifetime parameter then `i32: 'static` and
98+
`&'static str: 'a` are satisfied but `Vec<&'a ()>: 'static` is not.
99+
100+
## Higher-ranked trait bounds
101+
102+
Type bounds may be *higher ranked* over lifetimes. These bounds specify a bound
103+
is true *for all* lifetimes. For example, a bound such as `for<'a> &'a T:
104+
PartialEq<i32>` would require an implementation like
105+
106+
```rust,ignore
107+
impl<'a> PartialEq<i32> for &'a T {
108+
// ...
109+
}
110+
```
111+
112+
and could then be used to compare a `&'a T` with any lifetime to an `i32`.
113+
114+
Only a higher-ranked bound can be used here as the lifetime of the reference is
115+
shorter than a lifetime parameter on the function:
116+
117+
```rust
118+
fn call_on_ref_zero<F>(f: F) where for<'a> F: Fn(&'a i32) {
119+
let zero = 0;
120+
f(&zero);
121+
}
122+
```
123+
124+
Higher-ranked lifetimes may also be specified just before the trait, the only
125+
end of the following trait instead of the whole bound. This function is
126+
difference is the scope of the lifetime parameter, which extends only to the
127+
equivalent to the last one.
128+
129+
```rust
130+
fn call_on_ref_zero<F>(f: F) where F: for<'a> Fn(&'a i32) {
131+
let zero = 0;
132+
f(&zero);
27133
}
28134
```
135+
136+
> Warning: lifetime bounds are allowed on lifetimes in a `for` binder, but have
137+
> no effect: `for<'a, 'b: 'a>` is no different to `for<'a, 'b>`.
138+
139+
[LIFETIME_OR_LABEL]: tokens.html#lifetimes-and-loop-labels
140+
[_TraitPath_]: paths.html
141+
[`Sized`]: special-types-and-traits.html#sized
142+
143+
[associated types]: items/associated-items.html#associated-types
144+
[supertraits]: items/traits.html#supertraits
145+
[generic]: items/generics.html
146+
[Trait]: traits.html#trait-bounds
147+
[trait objects]: types.html#trait-objects
148+
[where clause]: items/where-clauses.html

Diff for: ‎src/types.md

+4-7
Original file line numberDiff line numberDiff line change
@@ -334,7 +334,7 @@ let foo_ptr_2 = if want_i32 {
334334
};
335335
```
336336

337-
All function items implement [Fn], [FnMut], [FnOnce], [Copy], [Clone], [Send],
337+
All function items implement [Fn], [FnMut], [FnOnce], [Copy], [Clone], [Send],
338338
and [Sync].
339339

340340
## Function pointer types
@@ -420,7 +420,7 @@ order to capture a single field:
420420

421421
```rust
422422
# use std::collections::HashSet;
423-
#
423+
#
424424
struct SetVec {
425425
set: HashSet<u32>,
426426
vec: Vec<u32>
@@ -500,10 +500,7 @@ Because captures are often by reference, the following general rules arise:
500500

501501
> **<sup>Syntax</sup>**
502502
> _TraitObjectType_ :
503-
> &nbsp;&nbsp; _LifetimeOrPath_ ( `+` _LifetimeOrPath_ )<sup>\*</sup> `+`<sup>?</sup>
504-
>
505-
> _LifetimeOrPath_ :
506-
> &nbsp;&nbsp; [_Path_] | [_LIFETIME_OR_LABEL_]
503+
> &nbsp;&nbsp; _TypeParamBounds_
507504
508505
A *trait object* is an opaque value of another type that implements a set of
509506
traits. The set of traits is made up of an [object safe] *base trait* plus any
@@ -653,4 +650,4 @@ impl Printable for String {
653650
[issue 47010]: https://github.com/rust-lang/rust/issues/47010
654651
[issue 33140]: https://github.com/rust-lang/rust/issues/33140
655652
[_PATH_]: paths.html
656-
[_LIFETIME_OR_LABEL_]: tokens.html#lifetimes-and-loop-labels
653+
[_LIFETIME_OR_LABEL_]: tokens.html#lifetimes-and-loop-labels

0 commit comments

Comments
 (0)
Please sign in to comment.