17
17
> _ ConstParam_ :\
18
18
>   ;  ; ` const ` [ IDENTIFIER] ` : ` [ _ Type_ ]
19
19
20
- Functions, type aliases, structs, enumerations, unions, traits, and
21
- implementations may be * parameterized* by types, constants, and lifetimes. These
20
+ [ Functions] , [ type aliases] , [ structs] , [ enumerations] , [ unions] , [ traits] , and
21
+ [ implementations] may be * parameterized* by types, constants, and lifetimes. These
22
22
parameters are listed in angle <span class =" parenthetical " >brackets (` <...> ` )</span >,
23
23
usually immediately after the name of the item and before its definition. For
24
24
implementations, which don't have a name, they come directly after ` impl ` .
@@ -33,22 +33,147 @@ struct Ref<'a, T> where T: 'a { r: &'a T }
33
33
struct InnerArray <T , const N : usize >([T ; N ]);
34
34
```
35
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
+
36
53
The only allowed types of const parameters are ` u8 ` , ` u16 ` , ` u32 ` , ` u64 ` , ` u128 ` , ` usize `
37
54
` i8 ` , ` i16 ` , ` i32 ` , ` i64 ` , ` i128 ` , ` isize ` , ` char ` and ` bool ` .
38
55
39
- Const parameters may only be be used as standalone arguments inside
40
- of [ types] and [ repeat expressions] but may be freely used elsewhere:
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.
41
118
42
119
``` rust,compile_fail
43
- // ok: standalone argument
44
- fn foo<const N: usize>() -> [u8; N] { todo!() }
120
+ // Examples where const parameters may not be used.
45
121
46
- // ERROR: generic const operation
47
- fn bar<const N: usize>() -> [u8; N + 1] { todo!() }
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
+ }
48
128
```
49
129
50
- Unlike type and lifetime parameters, const parameters of types can be used without
51
- being mentioned inside of a parameterized type:
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 interprted 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] :
52
177
53
178
``` rust,compile_fail
54
179
// ok
@@ -58,11 +183,29 @@ enum Bar<const M: usize> { A, B }
58
183
// ERROR: unused parameter
59
184
struct Baz<T>;
60
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
+ }
61
207
```
62
208
63
- [ References] , [ raw pointers] , [ arrays] , [ slices] [ arrays ] , [ tuples] , and
64
- [ function pointers] have lifetime or type parameters as well, but are not
65
- referred to with path syntax.
66
209
67
210
## Where clauses
68
211
@@ -90,7 +233,7 @@ parameters.
90
233
The ` for ` keyword can be used to introduce [ higher-ranked lifetimes] . It only
91
234
allows [ _ LifetimeParam_ ] parameters.
92
235
93
- Bounds that don't use the item's parameters or higher-ranked lifetimes are
236
+ Bounds that don't use the item's parameters or [ higher-ranked lifetimes] are
94
237
checked when the item is defined. It is an error for such a bound to be false.
95
238
96
239
[ ` Copy ` ] , [ ` Clone ` ] , and [ ` Sized ` ] bounds are also checked for certain generic
@@ -141,17 +284,35 @@ struct Foo<#[my_flexible_clone(unbounded)] H> {
141
284
[ _Type_ ] : ../types.md#type-expressions
142
285
[ _TypeParamBounds_ ] : ../trait-bounds.md
143
286
287
+ [ array repeat expression ] : ../expressions/array-expr.md
144
288
[ arrays ] : ../types/array.md
289
+ [ associated const ] : associated-items.md#associated-constants
290
+ [ associated type ] : associated-items.md#associated-types
291
+ [ block ] : ../expressions/block-expr.md
145
292
[ const contexts ] : ../const_eval.md#const-context
293
+ [ const expression ] : ../const_eval.md#constant-expressions
294
+ [ const item ] : constant-items.md
295
+ [ enumerations ] : enumerations.md
296
+ [ functions ] : functions.md
146
297
[ function pointers ] : ../types/function-pointer.md
298
+ [ generic implementations ] : implementations.md#generic-implementations
147
299
[ higher-ranked lifetimes ] : ../trait-bounds.md#higher-ranked-trait-bounds
300
+ [ implementations ] : implementations.md
301
+ [ item declarations ] : ../statements.md#item-declarations
302
+ [ item ] : ../items.md
303
+ [ literal ] : ../expressions/literal-expr.md
304
+ [ path ] : ../paths.md
305
+ [ path expression ] : ../expressions/path-expr.md
148
306
[ raw pointers ] : ../types/pointer.md#raw-pointers-const-and-mut
149
307
[ references ] : ../types/pointer.md#shared-references-
150
- [ repeat expressions ] : ../expressions/array-expr.md
151
308
[ `Clone` ] : ../special-types-and-traits.md#clone
152
309
[ `Copy` ] : ../special-types-and-traits.md#copy
153
310
[ `Sized` ] : ../special-types-and-traits.md#sized
311
+ [ structs ] : structs.md
154
312
[ tuples ] : ../types/tuple.md
155
313
[ trait object ] : ../types/trait-object.md
156
- [ types ] : ../types.md
314
+ [ traits ] : traits.md
315
+ [ type aliases ] : type-aliases.md
316
+ [ type ] : ../types.md
317
+ [ unions ] : unions.md
157
318
[ attributes ] : ../attributes.md
0 commit comments