]> git.proxmox.com Git - rustc.git/blob - src/doc/reference/src/items/generics.md
New upstream version 1.55.0+dfsg1
[rustc.git] / src / doc / reference / src / items / generics.md
1 # Generic parameters
2
3 > **<sup>Syntax</sup>**\
4 > _GenericParams_ :\
5 > &nbsp;&nbsp; &nbsp;&nbsp; `<` `>`\
6 > &nbsp;&nbsp; | `<` (_GenericParam_ `,`)<sup>\*</sup> _GenericParam_ `,`<sup>?</sup> `>`
7 >
8 > _GenericParam_ :\
9 > &nbsp;&nbsp; [_OuterAttribute_]<sup>\*</sup> ( _LifetimeParam_ | _TypeParam_ | _ConstParam_ )
10 >
11 > _LifetimeParam_ :\
12 > &nbsp;&nbsp; [LIFETIME_OR_LABEL]&nbsp;( `:` [_LifetimeBounds_] )<sup>?</sup>
13 >
14 > _TypeParam_ :\
15 > &nbsp;&nbsp; [IDENTIFIER]( `:` [_TypeParamBounds_]<sup>?</sup> )<sup>?</sup> ( `=` [_Type_] )<sup>?</sup>
16 >
17 > _ConstParam_:\
18 > &nbsp;&nbsp; `const` [IDENTIFIER] `:` [_Type_]
19
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>,
23 usually immediately after the name of the item and before its definition. For
24 implementations, which don't have a name, they come directly after `impl`.
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:
28
29 ```rust
30 fn foo<'a, T>() {}
31 trait A<U> {}
32 struct Ref<'a, T> where T: 'a { r: &'a T }
33 struct InnerArray<T, const N: usize>([T; N]);
34 ```
35
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
40 [References], [raw pointers], [arrays], [slices][arrays], [tuples], and
41 [function pointers] have lifetime or type parameters as well, but are not
42 referred to with path syntax.
43
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
169 // Can be fixed by wrapping in braces to force it to be interpreted as the `N`
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
210 ## Where clauses
211
212 > **<sup>Syntax</sup>**\
213 > _WhereClause_ :\
214 > &nbsp;&nbsp; `where` ( _WhereClauseItem_ `,` )<sup>\*</sup> _WhereClauseItem_ <sup>?</sup>
215 >
216 > _WhereClauseItem_ :\
217 > &nbsp;&nbsp; &nbsp;&nbsp; _LifetimeWhereClauseItem_\
218 > &nbsp;&nbsp; | _TypeBoundWhereClauseItem_
219 >
220 > _LifetimeWhereClauseItem_ :\
221 > &nbsp;&nbsp; [_Lifetime_] `:` [_LifetimeBounds_]
222 >
223 > _TypeBoundWhereClauseItem_ :\
224 > &nbsp;&nbsp; [_ForLifetimes_]<sup>?</sup> [_Type_] `:` [_TypeParamBounds_]<sup>?</sup>
225
226 *Where clauses* provide another way to specify bounds on type and lifetime
227 parameters as well as a way to specify bounds on types that aren't type
228 parameters.
229
230 The `for` keyword can be used to introduce [higher-ranked lifetimes]. It only
231 allows [_LifetimeParam_] parameters.
232
233 ```rust
234 struct A<T>
235 where
236 T: Iterator, // Could use A<T: Iterator> instead
237 T::Item: Copy, // Bound on an associated type
238 String: PartialEq<T>, // Bound on `String`, using the type parameter
239 i32: Default, // Allowed, but not useful
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
254 <!-- ignore: requires proc macro derive -->
255 ```rust,ignore
256 // Assume that the derive for MyFlexibleClone declared `my_flexible_clone` as
257 // an attribute it understands.
258 #[derive(MyFlexibleClone)]
259 struct Foo<#[my_flexible_clone(unbounded)] H> {
260 a: *const H
261 }
262 ```
263
264 [IDENTIFIER]: ../identifiers.md
265 [LIFETIME_OR_LABEL]: ../tokens.md#lifetimes-and-loop-labels
266
267 [_ForLifetimes_]: ../trait-bounds.md#higher-ranked-trait-bounds
268 [_LifetimeParam_]: #generic-parameters
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
275 [array repeat expression]: ../expressions/array-expr.md
276 [arrays]: ../types/array.md
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
285 [function pointers]: ../types/function-pointer.md
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
294 [raw pointers]: ../types/pointer.md#raw-pointers-const-and-mut
295 [references]: ../types/pointer.md#shared-references-
296 [structs]: structs.md
297 [tuples]: ../types/tuple.md
298 [trait object]: ../types/trait-object.md
299 [traits]: traits.md
300 [type aliases]: type-aliases.md
301 [type]: ../types.md
302 [unions]: unions.md
303 [attributes]: ../attributes.md