Skip to content

Commit 80000d4

Browse files
committed
More docs for generic parameters and trait bounds
1 parent f6d6871 commit 80000d4

File tree

3 files changed

+229
-40
lines changed

3 files changed

+229
-40
lines changed

src/items/generics.md

Lines changed: 105 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,107 @@
1-
# Type Parameters
1+
# Type and Lifetime Parameters
2+
3+
> **<sup>Syntax</sup>**
4+
> _Generics_ :
5+
> &nbsp;&nbsp; `<` _GenericParams_ <sup>?</sup> `>`
6+
>
7+
> _GenericParams_ :
8+
> &nbsp;&nbsp; &nbsp;&nbsp; _LifetimeParams_
9+
> &nbsp;&nbsp; | ( _LifetimeParams_ `,` ) <sup>?</sup>
10+
> _TypeParams_ `,` <sup>?</sup>
11+
>
12+
> _LifetimeParams_ :
13+
> &nbsp;&nbsp; _LifetimeParam_ (`,` _LifetimeParam_)<sup>\*</sup>
14+
>
15+
> _LifetimeParam_ :
16+
> &nbsp;&nbsp; [LIFETIME_OR_LABEL] [_LifetimeBounds_]<sup>?</sup>
17+
>
18+
> _Lifetime_ :
19+
> &nbsp;&nbsp; &nbsp;&nbsp; [LIFETIME_OR_LABEL]
20+
> &nbsp;&nbsp; | `'static`
21+
>
22+
> _TypeParams_:
23+
> &nbsp;&nbsp; _TypeParam_ (`,` _TypeParam_)<sup>\*</sup>
24+
>
25+
> _TypeParam_ :
26+
> &nbsp;&nbsp; [IDENTIFIER] [_TypeParamBounds_]<sup>?</sup> ( `=` [_Type_] )<sup>?</sup>
227
328
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
29+
implementations may be *parameterized* by types and lifetimes. These parameters
30+
are listed in angle brackets (`<...>`), after the name of the item (except for
31+
implementations, where they come directly after `impl`) and before its
32+
definition. Lifetime parameters must be declared before type parameters.
33+
Some examples of items with type and lifetime parameters:
34+
35+
```rust
36+
fn foo<'a, T>() {}
37+
trait A<U> {}
38+
struct Ref<'a, T> where T: 'a { r: &'a T }
39+
```
40+
41+
Certain built in types: [references], [raw pointers], [arrays],
42+
[slices][arrays], [tuples] and [function pointers], have lifetime or type
43+
parameters as well, but use different syntax.
44+
45+
## Where clauses
46+
47+
> **<sup>Syntax</sup>**
48+
> _WhereClause_ :
49+
> &nbsp;&nbsp; `where` ( _WhereClauseItem_ ( `,` _WhereClauseItem_ )<sup>\*</sup> `,`<sup>?</sup> )<sup>?</sup>
50+
>
51+
> _WhereClauseItem_ :
52+
> &nbsp;&nbsp; &nbsp;&nbsp; _LifetimeWhereClauseItem_
53+
> &nbsp;&nbsp; | _TypeBoundWhereClauseItem_
54+
>
55+
> _LifetimeWhereClauseItem_ :
56+
> &nbsp;&nbsp; [_Lifetime_](#type-and-lifetime-parameters) [_LifetimeBounds_]
57+
>
58+
> _TypeBoundWhereClauseItem_ :
59+
> &nbsp;&nbsp; _ForLifetimes_<sup>?</sup> [_Type_] `:` [_TypeParamBounds_]
60+
61+
Where clauses provide an alternative way to specify bounds on type and lifetime
62+
parameters, as well as a way to specify bounds on types that aren't type
63+
parameters.
64+
65+
Bounds that don't use the item's parameters are checked when the item is
66+
defined. It is an error for such a bound to be false.
67+
68+
[`Copy`], [`Clone`] and [`Sized`] bounds are checked more eagerly. It is an
69+
error to have `Copy` or `Clone`as a bound on a mutable reference, trait object,
70+
slice or string slice or `Sized` as a bound on a trait object, slice or string
71+
slice. `?Sized` may only be a bound on a type parameter.
72+
73+
```rust,ignore
74+
struct A<T>
75+
where
76+
T: Iterator, // Could use A<T: Iterator> instead
77+
T::Item: Copy,
78+
String: PartialEq<T>,
79+
i32: Default, // Allowed, but not useful
80+
i32: Iterator, // Error: the trait bound is not satisfied
81+
[T]: Copy, // Error: the trait bound is not satisfied
82+
[T]: ?Sized, // Error
83+
{
84+
f: T,
85+
}
86+
```
87+
88+
[IDENTIFIER]: identifiers.html
89+
[LIFETIME_OR_LABEL]: tokens.html#lifetimes-and-loop-labels
90+
91+
[_LifetimeBounds_]: trait-bounds.hmtl
92+
[_Type_]: types.html
93+
[_TypeParamBounds_]: trait-bounds.html
94+
95+
[arrays]: types.html#array-and-slice-types
96+
[function pointers]: types.html#function-pointer-types
97+
[references]: types.html#shared-references-
98+
[raw pointers]: types.html#raw-pointers-const-and-mut
99+
[`Clone`]: special-types-and-traits.html#clone
100+
[`Copy`]: special-types-and-traits.html#copy
101+
[`Sized`]: special-types-and-traits.html#sized
102+
[tuples]: types.html#tuple-types
103+
104+
[elision]: ../lifetime-elision.html
105+
[path]: ../paths.html
106+
[Trait]: traits.html#trait-bounds
107+
[_TypePath_]: paths.html

src/trait-bounds.md

Lines changed: 120 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,131 @@
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>[^sized_only]
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_] ( `+` [_Lifetime_] )<sup>\*</sup> `+`<sup>?</sup>
518
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.
19+
[Trait] and lifetime bounds provide a way for [generic items][generic] to
20+
restrict which types and lifetimes are used as their parameters. Bounds can be
21+
provided on any type in a [where clause]. There are also shorter alternative
22+
forms:
1323

14-
For example:
24+
* Bounds written after declaring a [generic parameter][generic]:
25+
`fn f<A: Copy>() {}` is the same as `fn f<A> where A: Copy () {}`.
26+
* In trait declarations as [supertraits]: `trait Circle : Shape {}` is
27+
equivalent to `trait Circle where Self : Shape {}`.
28+
* In trait declarations as bounds on [associated types]:
29+
`trait A { type B: Copy; }` is equivalent to
30+
`trait A where Self::B: Copy { type B; }`.
31+
32+
Bounds on an item must be satisfied when using the item. When type checking
33+
and borrow checking the item, the bounds can be used to prove that a type
34+
implements a required bound.
1535

1636
```rust
1737
# type Surface = i32;
18-
# trait Shape { fn draw(&self, Surface); }
19-
struct Figure<S: Shape>(S, S);
38+
trait Shape {
39+
fn draw(&self, Surface);
40+
fn name() -> &'static str;
41+
}
42+
2043
fn draw_twice<T: Shape>(surface: Surface, sh: T) {
44+
sh.draw(surface); // Can call method because T: Shape
2145
sh.draw(surface);
22-
sh.draw(surface);
2346
}
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
47+
48+
fn copy_and_draw_twice<T: Copy>(surface: Surface, sh: T) where T: Shape {
49+
let shape_copy = sh; // doesn't move sh because T: Copy
50+
draw_twice(surface, sh); // Can use generic function because T: Shape
51+
}
52+
53+
struct Figure<S: Shape>(S, S);
54+
55+
fn name_figure<U: Shape>(
56+
figure: Figure<U>, // Type Figure<U> is well-formed because U: Shape
57+
) {
58+
println!(
59+
"Figure of two {}",
60+
U::name(), // Can use associated function
61+
);
62+
}
63+
```
64+
65+
Trait and lifetime bounds are also used to name [trait objects].
66+
67+
> [^sized_only] `?` is only used to declare that the [`Sized`] trait may not be
68+
> implemented for a type parameter or associated type.
69+
70+
## Lifetime bounds
71+
72+
Lifetime bounds can be applied to other lifetimes, or to types. The bound
73+
`'a: 'b` is usually read as `'a` *outlives* `'b`. `'a: 'b` means that `'a`
74+
includes all points in the code that `'b` does.
75+
76+
```rust
77+
fn f<'a, 'b>(x: &'a i32, mut y: &'b i32) where 'a: 'b {
78+
y = x; // &'a i32 is a subtype of &'b i32 because 'a: 'b
79+
let r: &'b &'a i32 = &&0; // &'b &'a i32 is well formed because 'a: 'b
80+
}
81+
```
82+
83+
`T: 'a` means that all lifetime parameters of `T` outlive `'a`. For example if
84+
`'a` is an unconstrained lifetime parameter then `i32: 'static` and
85+
`&'static str: 'a` are satisfied but `Vec<&'a ()>: 'static` is not.
86+
87+
## Higher-ranked trait bounds
88+
89+
> **<sup>Syntax</sup>**
90+
> _ForLifetimes_ :
91+
> &nbsp;&nbsp; `for` `<` ( [_LifetimeParams_][generic][^unused_for_bounds]
92+
> `,`<sup>?</sup> ) <sup>?</sup> `>`
93+
94+
Type bounds may be *higher ranked* over lifetimes. A bound such as `for<'a> &'a
95+
T: PartialEq<T>` can be used to show `&'a T: PartialEq<T>` for any lifetime.
96+
For example, only a higher-ranked bound can be used here as the lifetime of the
97+
reference is shorter than any lifetime parameter on the function:
98+
99+
```rust
100+
fn call_on_ref_zero<F>(f: F) where for<'a> F: Fn(&'a i32) {
101+
let zero = 0;
102+
f(&zero);
27103
}
28104
```
105+
106+
Higher-ranked lifetimes may also be specified just before the trait, the only
107+
difference is the scope of the lifetime parameter, which extends only to the
108+
end of the following trait instead of the whole bound. This function is
109+
equivalent to the last one.
110+
111+
```rust
112+
fn call_on_ref_zero<F>(f: F) where F: for<'a> Fn(&'a i32) {
113+
let zero = 0;
114+
f(&zero);
115+
}
116+
```
117+
118+
> [^unused_for_bounds]Warning: lifetime bounds are allowed on lifetimes in a
119+
> `for` binder, but have no effect: `for<'a, 'b: 'a>` is no different to
120+
> `for<'a, 'b>`.
121+
122+
[_Lifetime_]: items/generics.html
123+
[_TraitPath_]: paths.html
124+
[`Sized`]: special-types-and-traits.html#sized
125+
126+
[associated types]: items/associated-items.html#associated-types
127+
[supertraits]: items/traits.html#supertraits
128+
[generic]: items/generics.html
129+
[Trait]: traits.html#trait-bounds
130+
[trait objects]: types.html#trait-objects
131+
[where clause]: items/where-clauses.html

src/types.md

Lines changed: 4 additions & 7 deletions
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)