]> git.proxmox.com Git - rustc.git/blame - src/doc/reference/src/items/generics.md
New upstream version 1.55.0+dfsg1
[rustc.git] / src / doc / reference / src / items / generics.md
CommitLineData
5869c6ff 1# Generic parameters
94b46f34 2
8faf50e0 3> **<sup>Syntax</sup>**\
8faf50e0 4> _GenericParams_ :\
5869c6ff
XL
5> &nbsp;&nbsp; &nbsp;&nbsp; `<` `>`\
6> &nbsp;&nbsp; | `<` (_GenericParam_ `,`)<sup>\*</sup> _GenericParam_ `,`<sup>?</sup> `>`
8faf50e0 7>
5869c6ff
XL
8> _GenericParam_ :\
9> &nbsp;&nbsp; [_OuterAttribute_]<sup>\*</sup> ( _LifetimeParam_ | _TypeParam_ | _ConstParam_ )
8faf50e0
XL
10>
11> _LifetimeParam_ :\
5869c6ff 12> &nbsp;&nbsp; [LIFETIME_OR_LABEL]&nbsp;( `:` [_LifetimeBounds_] )<sup>?</sup>
8faf50e0
XL
13>
14> _TypeParam_ :\
5869c6ff
XL
15> &nbsp;&nbsp; [IDENTIFIER]( `:` [_TypeParamBounds_]<sup>?</sup> )<sup>?</sup> ( `=` [_Type_] )<sup>?</sup>
16>
17> _ConstParam_:\
18> &nbsp;&nbsp; `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
22parameters are listed in angle <span class="parenthetical">brackets (`<...>`)</span>,
532ac7d7 23usually immediately after the name of the item and before its definition. For
94b46f34 24implementations, which don't have a name, they come directly after `impl`.
5869c6ff
XL
25The order of generic parameters is restricted to lifetime parameters, then type parameters, and then const parameters.
26
27Some examples of items with type, const, and lifetime parameters:
94b46f34
XL
28
29```rust
30fn foo<'a, T>() {}
31trait A<U> {}
32struct Ref<'a, T> where T: 'a { r: &'a T }
5869c6ff 33struct InnerArray<T, const N: usize>([T; N]);
94b46f34
XL
34```
35
5869c6ff
XL
36Generic parameters are in scope within the item definition where they are
37declared. They are not in scope for items declared within the body of a
38function 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
42referred to with path syntax.
43
5869c6ff
XL
44### Const generics
45
46*Const generic parameters* allow items to be generic over constant values. The
47const identifier introduces a name for the constant parameter, and all
48instances 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
53The only allowed types of const parameters are `u8`, `u16`, `u32`, `u64`, `u128`, `usize`
54`i8`, `i16`, `i32`, `i64`, `i128`, `isize`, `char` and `bool`.
55
56Const parameters can be used anywhere a [const item] can be used, with the
57exception that when used in a [type] or [array repeat expression], it must be
58standalone (as described below). That is, they are allowed in the following
59places:
60
611. As an applied const to any type which forms a part of the signature of the
62 item in question.
632. As part of a const expression used to define an [associated const], or as a
64 parameter to an [associated type].
653. As a value in any runtime expression in the body of any functions in the
66 item.
674. As a parameter to any type used in the body of any functions in the item.
685. 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.
74fn 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.
82struct Foo<const N: usize>([i32; N]);
83
84impl<const N: usize> Foo<N> {
85 // Used as an associated constant.
86 const CONST: usize = N * 4;
87}
88
89trait Trait {
90 type Output;
91}
92
93impl<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.
101fn 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
113As a further restriction, const parameters may only appear as a standalone
114argument inside of a [type] or [array repeat expression]. In those contexts,
115they 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
117expressions.
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.
124fn bad_function<const N: usize>() -> [u8; {N + 1}] {
125 // Similarly not allowed for array repeat expressions.
126 [1; {N + 1}]
127}
128```
129
130A const argument in a [path] specifies the const value to use for that item.
131The argument must be a [const expression] of the type ascribed to the const
132parameter. The const expression must be a [block expression][block]
133(surrounded with braces) unless it is a single path segment (an [IDENTIFIER])
134or 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
140fn double<const N: i32>() {
141 println!("doubled: {}", N * 2);
142}
143
144const SOME_CONST: i32 = 12;
145
146fn 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
156When there is ambiguity if a generic argument could be resolved as either a
157type or const argument, it is always resolved as a type. Placing the argument
158in 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
165type N = u32;
166struct Foo<const N: usize>;
167// The following is an error, because `N` is interpreted as the type alias `N`.
168fn 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:
171fn bar<const N: usize>() -> Foo<{ N }> { todo!() } // ok
172```
173
174Unlike type and lifetime parameters, const parameters can be declared without
175being used inside of a parameterized item, with the exception of
176implementations as described in [generic implementations]:
177
178```rust,compile_fail
179// ok
180struct Foo<const N: usize>;
181enum Bar<const M: usize> { A, B }
182
183// ERROR: unused parameter
184struct Baz<T>;
185struct Biz<'a>;
186struct Unconstrained;
187impl<const N: usize> Unconstrained {}
188```
189
190When resolving a trait bound obligation, the exhaustiveness of all
191implementations of const parameters is not considered when determining if the
192bound is satisfied. For example, in the following, even though all possible
193const values for the `bool` type are implemented, it is still an error that
194the trait bound is not satisfied:
195
196```rust,compile_fail
197struct Foo<const B: bool>;
198trait Bar {}
199impl Bar for Foo<true> {}
200impl Bar for Foo<false> {}
201
202fn needs_bar(_: impl Bar) {}
203fn 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> &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_ :\
17df50a5 224> &nbsp;&nbsp; [_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
227parameters as well as a way to specify bounds on types that aren't type
228parameters.
229
5869c6ff
XL
230The `for` keyword can be used to introduce [higher-ranked lifetimes]. It only
231allows [_LifetimeParam_] parameters.
232
136023e0 233```rust
94b46f34
XL
234struct A<T>
235where
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
247Generic lifetime and type parameters allow [attributes] on them. There are no
248built-in attributes that do anything in this position, although custom derive
249attributes may give meaning to it.
250
251This example shows using a custom derive attribute to modify the meaning of a
252generic 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)]
259struct 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