27
27
> _ ConstParam_ :\
28
28
>   ;  ; [ _ OuterAttribute_ ] <sup >?</sup > ` const ` [ IDENTIFIER] ` : ` [ _ Type_ ]
29
29
30
- Functions, type aliases, structs, enumerations, unions, traits, and
31
- implementations may be * parameterized* by types, constants, and lifetimes. These
30
+ [ Functions] , [ type aliases] , [ structs] , [ enumerations] , [ unions] , [ traits] , and
31
+ [ implementations] may be * parameterized* by types, constants, and lifetimes. These
32
32
parameters are listed in angle <span class =" parenthetical " >brackets (` <...> ` )</span >,
33
33
usually immediately after the name of the item and before its definition. For
34
34
implementations, which don't have a name, they come directly after ` impl ` .
@@ -43,18 +43,137 @@ struct Ref<'a, T> where T: 'a { r: &'a T }
43
43
struct InnerArray <T , const N : usize >([T ; N ]);
44
44
```
45
45
46
+ The generic parameters are in scope within the item definition where they are
47
+ declared.
48
+
49
+ [ References] , [ raw pointers] , [ arrays] , [ slices] [ arrays ] , [ tuples] , and
50
+ [ function pointers] have lifetime or type parameters as well, but are not
51
+ referred to with path syntax.
52
+
53
+ ### Const generics
54
+
55
+ Const generic parameters allow items to be generic over constant values. The
56
+ const identifier introduces a name for the constant parameter, and all
57
+ instances of the item must be instantiated with a value of the given type.
58
+
59
+ <!-- TODO: update above to say "introduces a name in the [value namespace]"
60
+ once namespaces are added. -->
61
+
46
62
The only allowed types of const parameters are ` u8 ` , ` u16 ` , ` u32 ` , ` u64 ` , ` u128 ` , ` usize `
47
63
` i8 ` , ` i16 ` , ` i32 ` , ` i64 ` , ` i128 ` , ` isize ` , ` char ` and ` bool ` .
48
64
49
- Const parameters may only be be used as standalone arguments inside
50
- of [ types] and [ repeat expressions] but may be freely used elsewhere:
65
+ Const parameters can generally be used anywhere a [ const item] can be used,
66
+ with the exception of the definition of any [ item] within the body of a
67
+ function, and can only be used as standalone expressions in [ types] and
68
+ [ array repeat expressions] (described below). That is, they are allowed in the
69
+ following places:
70
+
71
+ 1 . As an applied const to any type which forms a part of the signature of the
72
+ item in question.
73
+ 2 . As part of a const expression used to define an [ associated const] , or as a
74
+ parameter to an [ associated type] .
75
+ 3 . As a value in any runtime expression in the body of any functions in the
76
+ item.
77
+ 4 . As a parameter to any type used in the body of any functions in the item.
78
+ 5 . As a part of the type of any fields in the item.
79
+
80
+ ``` rust
81
+ // Examples where const generic parameters can be used.
82
+
83
+ // Used in the signature of the item itself.
84
+ fn foo <const N : usize >(arr : [i32 ; N ]) {
85
+ // Used as a type within a function body.
86
+ let x : [i32 ; N ];
87
+ // Used as an expression.
88
+ println! (" {}" , N * 2 );
89
+ }
90
+
91
+ // Used as a field of a struct.
92
+ struct Foo <const N : usize >([i32 ; N ]);
93
+
94
+ impl <const N : usize > Foo <N > {
95
+ // Used as an associated constant.
96
+ const CONST : usize = N * 4 ;
97
+ }
98
+
99
+ trait Trait {
100
+ type Output ;
101
+ }
102
+
103
+ impl <const N : usize > Trait for Foo <N > {
104
+ // Used as an associated type.
105
+ type Output = [i32 ; N ];
106
+ }
107
+ ```
108
+
109
+ ``` rust,compile_fail
110
+ // Examples where const generic parameters cannot be used.
111
+ fn foo<const N: usize>() {
112
+ // Cannot use in item definitions within a function body.
113
+ const BAD_CONST: [usize; N] = [1; N];
114
+ static BAD_STATIC: [usize; N] = [1; N];
115
+ fn inner(bad_arg: [usize; N]) {
116
+ let bad_value = N * 2;
117
+ }
118
+ type BadAlias = [usize; N];
119
+ struct BadStruct([usize; N]);
120
+ }
121
+ ```
122
+
123
+ As a further restriction, const parameters may only appear as a standalone
124
+ argument inside of [ types] and [ array repeat expressions] . In those contexts,
125
+ they may only be used as a single segment [ path expression] , possibly inside a
126
+ [ block] (such as ` N ` or ` {N} ` ). That is, they cannot be combined with other
127
+ expressions.
51
128
52
129
``` rust,compile_fail
53
- // ok: standalone argument
54
- fn foo<const N: usize>() -> [u8; N] { todo!() }
130
+ // Examples where const parameters may not be used.
131
+
132
+ // Not allowed to combine in other expressions in types, such as the
133
+ // arithmetic expression in the return type here.
134
+ fn bad_function<const N: usize>() -> [u8; {N + 1}] {
135
+ // Similarly not allowed for array repeat expressions.
136
+ [1; {N + 1}]
137
+ }
138
+ ```
139
+
140
+ A const argument in a [ path] specifies the const value to use for that item.
141
+ The argument must be a [ const expression] of the type ascribed to the const
142
+ parameter. The const expression must be a [ block expression] [ block ]
143
+ (surrounded with braces) unless it is a single path segment (an [ IDENTIFIER] )
144
+ or a [ literal] (with a possibly leading ` - ` token). This syntactic restriction
145
+ is necessary to avoid requiring infinite lookahead when parsing an expression
146
+ inside of a type.
147
+
148
+ ``` rust
149
+ fn double <const N : i32 >() {
150
+ println! (" doubled: {}" , N * 2 );
151
+ }
55
152
56
- // ERROR: generic const operation
57
- fn bar<const N: usize>() -> [u8; N + 1] { todo!() }
153
+ const SOME_CONST : i32 = 12 ;
154
+
155
+ fn example () {
156
+ // Example usage of a const argument.
157
+ double :: <9 >();
158
+ double :: <- 123 >();
159
+ double :: <{7 + 8 }>();
160
+ double :: <SOME_CONST >();
161
+ double :: <{ SOME_CONST + 5 }>();
162
+ }
163
+ ```
164
+
165
+ When there is ambiguity if a generic argument could be resolved as either a
166
+ type or const argument, it is always resolved as a type. Placing the argument
167
+ in a block expression can force it to be interpreted as a const argument.
168
+
169
+ ``` rust,compile_fail
170
+ type N = u32;
171
+ struct Foo<const N: usize>;
172
+ // The following is an error, because `N` is interpreted as the type alias `N`.
173
+ fn foo<const N: usize>() -> Foo<N> { todo!() } // ERROR
174
+ // Can be fixed by wrapping in braces to force it to be interprted as the `N`
175
+ // const parameter:
176
+ fn bar<const N: usize>() -> Foo<{ N }> { todo!() } // ok
58
177
```
59
178
60
179
Unlike type and lifetime parameters, const parameters of types can be used without
@@ -70,10 +189,6 @@ struct Baz<T>;
70
189
struct Biz<'a>;
71
190
```
72
191
73
- [ References] , [ raw pointers] , [ arrays] , [ slices] [ arrays ] , [ tuples] , and
74
- [ function pointers] have lifetime or type parameters as well, but are not
75
- referred to with path syntax.
76
-
77
192
## Where clauses
78
193
79
194
> ** <sup >Syntax</sup >** \
@@ -97,7 +212,7 @@ referred to with path syntax.
97
212
parameters as well as a way to specify bounds on types that aren't type
98
213
parameters.
99
214
100
- Bounds that don't use the item's parameters or higher-ranked lifetimes are
215
+ Bounds that don't use the item's parameters or [ higher-ranked lifetimes] are
101
216
checked when the item is defined. It is an error for such a bound to be false.
102
217
103
218
[ ` Copy ` ] , [ ` Clone ` ] , and [ ` Sized ` ] bounds are also checked for certain generic
@@ -147,16 +262,33 @@ struct Foo<#[my_flexible_clone(unbounded)] H> {
147
262
[ _Type_ ] : ../types.md#type-expressions
148
263
[ _TypeParamBounds_ ] : ../trait-bounds.md
149
264
265
+ [ array repeat expressions ] : ../expressions/array-expr.md
150
266
[ arrays ] : ../types/array.md
267
+ [ associated const ] : associated-items.md#associated-constants
268
+ [ associated type ] : associated-items.md#associated-types
269
+ [ block ] : ../expressions/block-expr.md
151
270
[ const contexts ] : ../const_eval.md#const-context
271
+ [ const expression ] : ../const_eval.md#constant-expressions
272
+ [ const item ] : constant-items.md
273
+ [ enumerations ] : enumerations.md
274
+ [ functions ] : functions.md
152
275
[ function pointers ] : ../types/function-pointer.md
276
+ [ higher-ranked lifetimes ] : ../trait-bounds.md#higher-ranked-trait-bounds
277
+ [ implementations ] : implementations.md
278
+ [ item ] : ../items.md
279
+ [ literal ] : ../expressions/literal-expr.md
280
+ [ path ] : ../paths.md
281
+ [ path expression ] : ../expressions/path-expr.md
153
282
[ raw pointers ] : ../types/pointer.md#raw-pointers-const-and-mut
154
283
[ references ] : ../types/pointer.md#shared-references-
155
- [ repeat expressions ] : ../expressions/array-expr.md
156
284
[ `Clone` ] : ../special-types-and-traits.md#clone
157
285
[ `Copy` ] : ../special-types-and-traits.md#copy
158
286
[ `Sized` ] : ../special-types-and-traits.md#sized
287
+ [ structs ] : structs.md
159
288
[ tuples ] : ../types/tuple.md
160
289
[ trait object ] : ../types/trait-object.md
290
+ [ traits ] : traits.md
291
+ [ type aliases ] : type-aliases.md
161
292
[ types ] : ../types.md
293
+ [ unions ] : unions.md
162
294
[ attributes ] : ../attributes.md
0 commit comments