|
1 |
| -# Trait bounds |
| 1 | +# Trait and lifetime bounds |
2 | 2 |
|
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 | +> _TypeParamBound_ ( `+` _TypeParamBound_ )<sup>\*</sup> `+`<sup>?</sup> |
| 6 | +> |
| 7 | +> _TypeParamBound_ : |
| 8 | +> _Lifetime_ | _TraitBound_ |
| 9 | +> |
| 10 | +> _TraitBound_ : |
| 11 | +> `?`<sup>?</sup> |
| 12 | +> [_ForLifetimes_](#higher-ranked-trait-bounds)<sup>?</sup> [_TraitPath_] |
| 13 | +> | `(` `?`<sup>?</sup> |
| 14 | +> [_ForLifetimes_](#higher-ranked-trait-bounds)<sup>?</sup> [_TraitPath_] `)` |
| 15 | +> |
| 16 | +> _LifetimeBounds_ : |
| 17 | +> ( _Lifetime_ `+` )<sup>\*</sup> _Lifetime_<sup>?</sup> |
| 18 | +> |
| 19 | +> _Lifetime_ : |
| 20 | +> [LIFETIME_OR_LABEL] |
| 21 | +> | `'static` |
5 | 22 |
|
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: |
13 | 27 |
|
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`. |
15 | 45 |
|
16 | 46 | ```rust
|
17 | 47 | # 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 | + |
20 | 53 | fn draw_twice<T: Shape>(surface: Surface, sh: T) {
|
| 54 | + sh.draw(surface); // Can call method because T: Shape |
21 | 55 | sh.draw(surface);
|
22 |
| - sh.draw(surface); |
23 | 56 | }
|
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); |
27 | 133 | }
|
28 | 134 | ```
|
| 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 |
0 commit comments