]>
Commit | Line | Data |
---|---|---|
5869c6ff | 1 | # Generic parameters |
94b46f34 | 2 | |
8faf50e0 | 3 | > **<sup>Syntax</sup>**\ |
8faf50e0 | 4 | > _GenericParams_ :\ |
5869c6ff XL |
5 | > `<` `>`\ |
6 | > | `<` (_GenericParam_ `,`)<sup>\*</sup> _GenericParam_ `,`<sup>?</sup> `>` | |
8faf50e0 | 7 | > |
5869c6ff XL |
8 | > _GenericParam_ :\ |
9 | > [_OuterAttribute_]<sup>\*</sup> ( _LifetimeParam_ | _TypeParam_ | _ConstParam_ ) | |
8faf50e0 XL |
10 | > |
11 | > _LifetimeParam_ :\ | |
5869c6ff | 12 | > [LIFETIME_OR_LABEL] ( `:` [_LifetimeBounds_] )<sup>?</sup> |
8faf50e0 XL |
13 | > |
14 | > _TypeParam_ :\ | |
5869c6ff XL |
15 | > [IDENTIFIER]( `:` [_TypeParamBounds_]<sup>?</sup> )<sup>?</sup> ( `=` [_Type_] )<sup>?</sup> |
16 | > | |
17 | > _ConstParam_:\ | |
18 | > `const` [IDENTIFIER] `:` [_Type_] | |
94b46f34 | 19 | |
5869c6ff XL |
20 | [Functions], [type aliases], [structs], [enumerations], [unions], [traits], and |
21 | [implementations] may be *parameterized* by types, constants, and lifetimes. These | |
22 | parameters are listed in angle <span class="parenthetical">brackets (`<...>`)</span>, | |
532ac7d7 | 23 | usually immediately after the name of the item and before its definition. For |
94b46f34 | 24 | implementations, which don't have a name, they come directly after `impl`. |
5869c6ff XL |
25 | The order of generic parameters is restricted to lifetime parameters, then type parameters, and then const parameters. |
26 | ||
27 | Some examples of items with type, const, and lifetime parameters: | |
94b46f34 XL |
28 | |
29 | ```rust | |
30 | fn foo<'a, T>() {} | |
31 | trait A<U> {} | |
32 | struct Ref<'a, T> where T: 'a { r: &'a T } | |
5869c6ff | 33 | struct InnerArray<T, const N: usize>([T; N]); |
94b46f34 XL |
34 | ``` |
35 | ||
5869c6ff XL |
36 | Generic parameters are in scope within the item definition where they are |
37 | declared. They are not in scope for items declared within the body of a | |
38 | function as described in [item declarations]. | |
39 | ||
e1599b0c | 40 | [References], [raw pointers], [arrays], [slices][arrays], [tuples], and |
94b46f34 XL |
41 | [function pointers] have lifetime or type parameters as well, but are not |
42 | referred to with path syntax. | |
43 | ||
5869c6ff XL |
44 | ### Const generics |
45 | ||
46 | *Const generic parameters* allow items to be generic over constant values. The | |
47 | const identifier introduces a name for the constant parameter, and all | |
48 | instances of the item must be instantiated with a value of the given type. | |
49 | ||
50 | <!-- TODO: update above to say "introduces a name in the [value namespace]" | |
51 | once namespaces are added. --> | |
52 | ||
53 | The only allowed types of const parameters are `u8`, `u16`, `u32`, `u64`, `u128`, `usize` | |
54 | `i8`, `i16`, `i32`, `i64`, `i128`, `isize`, `char` and `bool`. | |
55 | ||
56 | Const parameters can be used anywhere a [const item] can be used, with the | |
57 | exception that when used in a [type] or [array repeat expression], it must be | |
58 | standalone (as described below). That is, they are allowed in the following | |
59 | places: | |
60 | ||
61 | 1. As an applied const to any type which forms a part of the signature of the | |
62 | item in question. | |
63 | 2. As part of a const expression used to define an [associated const], or as a | |
64 | parameter to an [associated type]. | |
65 | 3. As a value in any runtime expression in the body of any functions in the | |
66 | item. | |
67 | 4. As a parameter to any type used in the body of any functions in the item. | |
68 | 5. As a part of the type of any fields in the item. | |
69 | ||
70 | ```rust | |
71 | // Examples where const generic parameters can be used. | |
72 | ||
73 | // Used in the signature of the item itself. | |
74 | fn foo<const N: usize>(arr: [i32; N]) { | |
75 | // Used as a type within a function body. | |
76 | let x: [i32; N]; | |
77 | // Used as an expression. | |
78 | println!("{}", N * 2); | |
79 | } | |
80 | ||
81 | // Used as a field of a struct. | |
82 | struct Foo<const N: usize>([i32; N]); | |
83 | ||
84 | impl<const N: usize> Foo<N> { | |
85 | // Used as an associated constant. | |
86 | const CONST: usize = N * 4; | |
87 | } | |
88 | ||
89 | trait Trait { | |
90 | type Output; | |
91 | } | |
92 | ||
93 | impl<const N: usize> Trait for Foo<N> { | |
94 | // Used as an associated type. | |
95 | type Output = [i32; N]; | |
96 | } | |
97 | ``` | |
98 | ||
99 | ```rust,compile_fail | |
100 | // Examples where const generic parameters cannot be used. | |
101 | fn foo<const N: usize>() { | |
102 | // Cannot use in item definitions within a function body. | |
103 | const BAD_CONST: [usize; N] = [1; N]; | |
104 | static BAD_STATIC: [usize; N] = [1; N]; | |
105 | fn inner(bad_arg: [usize; N]) { | |
106 | let bad_value = N * 2; | |
107 | } | |
108 | type BadAlias = [usize; N]; | |
109 | struct BadStruct([usize; N]); | |
110 | } | |
111 | ``` | |
112 | ||
113 | As a further restriction, const parameters may only appear as a standalone | |
114 | argument inside of a [type] or [array repeat expression]. In those contexts, | |
115 | they may only be used as a single segment [path expression], possibly inside a | |
116 | [block] (such as `N` or `{N}`). That is, they cannot be combined with other | |
117 | expressions. | |
118 | ||
119 | ```rust,compile_fail | |
120 | // Examples where const parameters may not be used. | |
121 | ||
122 | // Not allowed to combine in other expressions in types, such as the | |
123 | // arithmetic expression in the return type here. | |
124 | fn bad_function<const N: usize>() -> [u8; {N + 1}] { | |
125 | // Similarly not allowed for array repeat expressions. | |
126 | [1; {N + 1}] | |
127 | } | |
128 | ``` | |
129 | ||
130 | A const argument in a [path] specifies the const value to use for that item. | |
131 | The argument must be a [const expression] of the type ascribed to the const | |
132 | parameter. The const expression must be a [block expression][block] | |
133 | (surrounded with braces) unless it is a single path segment (an [IDENTIFIER]) | |
134 | or a [literal] (with a possibly leading `-` token). | |
135 | ||
136 | > **Note**: This syntactic restriction is necessary to avoid requiring | |
137 | > infinite lookahead when parsing an expression inside of a type. | |
138 | ||
139 | ```rust | |
140 | fn double<const N: i32>() { | |
141 | println!("doubled: {}", N * 2); | |
142 | } | |
143 | ||
144 | const SOME_CONST: i32 = 12; | |
145 | ||
146 | fn example() { | |
147 | // Example usage of a const argument. | |
148 | double::<9>(); | |
149 | double::<-123>(); | |
150 | double::<{7 + 8}>(); | |
151 | double::<SOME_CONST>(); | |
152 | double::<{ SOME_CONST + 5 }>(); | |
153 | } | |
154 | ``` | |
155 | ||
156 | When there is ambiguity if a generic argument could be resolved as either a | |
157 | type or const argument, it is always resolved as a type. Placing the argument | |
158 | in a block expression can force it to be interpreted as a const argument. | |
159 | ||
160 | <!-- TODO: Rewrite the paragraph above to be in terms of namespaces, once | |
161 | namespaces are introduced, and it is clear which namespace each parameter | |
162 | lives in. --> | |
163 | ||
164 | ```rust,compile_fail | |
165 | type N = u32; | |
166 | struct Foo<const N: usize>; | |
167 | // The following is an error, because `N` is interpreted as the type alias `N`. | |
168 | fn foo<const N: usize>() -> Foo<N> { todo!() } // ERROR | |
6a06907d | 169 | // Can be fixed by wrapping in braces to force it to be interpreted as the `N` |
5869c6ff XL |
170 | // const parameter: |
171 | fn bar<const N: usize>() -> Foo<{ N }> { todo!() } // ok | |
172 | ``` | |
173 | ||
174 | Unlike type and lifetime parameters, const parameters can be declared without | |
175 | being used inside of a parameterized item, with the exception of | |
176 | implementations as described in [generic implementations]: | |
177 | ||
178 | ```rust,compile_fail | |
179 | // ok | |
180 | struct Foo<const N: usize>; | |
181 | enum Bar<const M: usize> { A, B } | |
182 | ||
183 | // ERROR: unused parameter | |
184 | struct Baz<T>; | |
185 | struct Biz<'a>; | |
186 | struct Unconstrained; | |
187 | impl<const N: usize> Unconstrained {} | |
188 | ``` | |
189 | ||
190 | When resolving a trait bound obligation, the exhaustiveness of all | |
191 | implementations of const parameters is not considered when determining if the | |
192 | bound is satisfied. For example, in the following, even though all possible | |
193 | const values for the `bool` type are implemented, it is still an error that | |
194 | the trait bound is not satisfied: | |
195 | ||
196 | ```rust,compile_fail | |
197 | struct Foo<const B: bool>; | |
198 | trait Bar {} | |
199 | impl Bar for Foo<true> {} | |
200 | impl Bar for Foo<false> {} | |
201 | ||
202 | fn needs_bar(_: impl Bar) {} | |
203 | fn generic<const B: bool>() { | |
204 | let v = Foo::<B>; | |
205 | needs_bar(v); // ERROR: trait bound `Foo<B>: Bar` is not satisfied | |
206 | } | |
207 | ``` | |
208 | ||
209 | ||
94b46f34 XL |
210 | ## Where clauses |
211 | ||
8faf50e0 XL |
212 | > **<sup>Syntax</sup>**\ |
213 | > _WhereClause_ :\ | |
214 | > `where` ( _WhereClauseItem_ `,` )<sup>\*</sup> _WhereClauseItem_ <sup>?</sup> | |
215 | > | |
216 | > _WhereClauseItem_ :\ | |
217 | > _LifetimeWhereClauseItem_\ | |
218 | > | _TypeBoundWhereClauseItem_ | |
219 | > | |
220 | > _LifetimeWhereClauseItem_ :\ | |
221 | > [_Lifetime_] `:` [_LifetimeBounds_] | |
222 | > | |
223 | > _TypeBoundWhereClauseItem_ :\ | |
17df50a5 | 224 | > [_ForLifetimes_]<sup>?</sup> [_Type_] `:` [_TypeParamBounds_]<sup>?</sup> |
94b46f34 | 225 | |
532ac7d7 | 226 | *Where clauses* provide another way to specify bounds on type and lifetime |
94b46f34 XL |
227 | parameters as well as a way to specify bounds on types that aren't type |
228 | parameters. | |
229 | ||
5869c6ff XL |
230 | The `for` keyword can be used to introduce [higher-ranked lifetimes]. It only |
231 | allows [_LifetimeParam_] parameters. | |
232 | ||
136023e0 | 233 | ```rust |
94b46f34 XL |
234 | struct A<T> |
235 | where | |
236 | T: Iterator, // Could use A<T: Iterator> instead | |
136023e0 XL |
237 | T::Item: Copy, // Bound on an associated type |
238 | String: PartialEq<T>, // Bound on `String`, using the type parameter | |
94b46f34 | 239 | i32: Default, // Allowed, but not useful |
94b46f34 XL |
240 | { |
241 | f: T, | |
242 | } | |
243 | ``` | |
244 | ||
245 | ## Attributes | |
246 | ||
247 | Generic lifetime and type parameters allow [attributes] on them. There are no | |
248 | built-in attributes that do anything in this position, although custom derive | |
249 | attributes may give meaning to it. | |
250 | ||
251 | This example shows using a custom derive attribute to modify the meaning of a | |
252 | generic parameter. | |
253 | ||
60c5eb7d | 254 | <!-- ignore: requires proc macro derive --> |
e74abb32 | 255 | ```rust,ignore |
94b46f34 XL |
256 | // Assume that the derive for MyFlexibleClone declared `my_flexible_clone` as |
257 | // an attribute it understands. | |
e74abb32 XL |
258 | #[derive(MyFlexibleClone)] |
259 | struct Foo<#[my_flexible_clone(unbounded)] H> { | |
94b46f34 XL |
260 | a: *const H |
261 | } | |
262 | ``` | |
263 | ||
416331ca XL |
264 | [IDENTIFIER]: ../identifiers.md |
265 | [LIFETIME_OR_LABEL]: ../tokens.md#lifetimes-and-loop-labels | |
266 | ||
17df50a5 | 267 | [_ForLifetimes_]: ../trait-bounds.md#higher-ranked-trait-bounds |
5869c6ff | 268 | [_LifetimeParam_]: #generic-parameters |
416331ca XL |
269 | [_LifetimeBounds_]: ../trait-bounds.md |
270 | [_Lifetime_]: ../trait-bounds.md | |
271 | [_OuterAttribute_]: ../attributes.md | |
272 | [_Type_]: ../types.md#type-expressions | |
273 | [_TypeParamBounds_]: ../trait-bounds.md | |
274 | ||
5869c6ff | 275 | [array repeat expression]: ../expressions/array-expr.md |
416331ca | 276 | [arrays]: ../types/array.md |
5869c6ff XL |
277 | [associated const]: associated-items.md#associated-constants |
278 | [associated type]: associated-items.md#associated-types | |
279 | [block]: ../expressions/block-expr.md | |
280 | [const contexts]: ../const_eval.md#const-context | |
281 | [const expression]: ../const_eval.md#constant-expressions | |
282 | [const item]: constant-items.md | |
283 | [enumerations]: enumerations.md | |
284 | [functions]: functions.md | |
416331ca | 285 | [function pointers]: ../types/function-pointer.md |
5869c6ff XL |
286 | [generic implementations]: implementations.md#generic-implementations |
287 | [higher-ranked lifetimes]: ../trait-bounds.md#higher-ranked-trait-bounds | |
288 | [implementations]: implementations.md | |
289 | [item declarations]: ../statements.md#item-declarations | |
290 | [item]: ../items.md | |
291 | [literal]: ../expressions/literal-expr.md | |
292 | [path]: ../paths.md | |
293 | [path expression]: ../expressions/path-expr.md | |
416331ca | 294 | [raw pointers]: ../types/pointer.md#raw-pointers-const-and-mut |
5869c6ff | 295 | [references]: ../types/pointer.md#shared-references- |
5869c6ff | 296 | [structs]: structs.md |
416331ca XL |
297 | [tuples]: ../types/tuple.md |
298 | [trait object]: ../types/trait-object.md | |
5869c6ff XL |
299 | [traits]: traits.md |
300 | [type aliases]: type-aliases.md | |
301 | [type]: ../types.md | |
302 | [unions]: unions.md | |
416331ca | 303 | [attributes]: ../attributes.md |