]> git.proxmox.com Git - rustc.git/blame - src/doc/reference/src/expressions/loop-expr.md
Merge 1.70 into proxmox/bookworm
[rustc.git] / src / doc / reference / src / expressions / loop-expr.md
CommitLineData
2b03887a 1# Loops and other breakable expressions
ea8adc8c 2
8faf50e0
XL
3> **<sup>Syntax</sup>**\
4> _LoopExpression_ :\
5> &nbsp;&nbsp; [_LoopLabel_]<sup>?</sup> (\
6> &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; [_InfiniteLoopExpression_]\
7> &nbsp;&nbsp; &nbsp;&nbsp; | [_PredicateLoopExpression_]\
8> &nbsp;&nbsp; &nbsp;&nbsp; | [_PredicatePatternLoopExpression_]\
9> &nbsp;&nbsp; &nbsp;&nbsp; | [_IteratorLoopExpression_]\
2b03887a 10> &nbsp;&nbsp; &nbsp;&nbsp; | [_LabelBlockExpression_]\
8faf50e0 11> &nbsp;&nbsp; )
ff7c6d11
XL
12
13[_LoopLabel_]: #loop-labels
14[_InfiniteLoopExpression_]: #infinite-loops
15[_PredicateLoopExpression_]: #predicate-loops
16[_PredicatePatternLoopExpression_]: #predicate-pattern-loops
17[_IteratorLoopExpression_]: #iterator-loops
2b03887a 18[_LabelBlockExpression_]: #labelled-block-expressions
ff7c6d11 19
2b03887a 20Rust supports five loop expressions:
ea8adc8c
XL
21
22* A [`loop` expression](#infinite-loops) denotes an infinite loop.
23* A [`while` expression](#predicate-loops) loops until a predicate is false.
532ac7d7 24* A [`while let` expression](#predicate-pattern-loops) tests a pattern.
6a06907d 25* A [`for` expression](#iterator-loops) extracts values from an iterator, looping until the iterator is empty.
2b03887a 26* A [labelled block expression](#labelled-block-expressions) runs a loop exactly once, but allows exiting the loop early with `break`.
ea8adc8c 27
2b03887a
FG
28All five types of loop support [`break` expressions](#break-expressions), and [labels](#loop-labels).
29All except labelled block expressions support [`continue` expressions](#continue-expressions).
30Only `loop` and labelled block expressions support [evaluation to non-trivial values](#break-and-loop-values).
ea8adc8c
XL
31
32## Infinite loops
33
8faf50e0
XL
34> **<sup>Syntax</sup>**\
35> _InfiniteLoopExpression_ :\
ff7c6d11
XL
36> &nbsp;&nbsp; `loop` [_BlockExpression_]
37
ea8adc8c
XL
38A `loop` expression repeats execution of its body continuously:
39`loop { println!("I live."); }`.
40
6a06907d
XL
41A `loop` expression without an associated `break` expression is diverging and has type [`!`](../types/never.md).
42A `loop` expression containing associated [`break` expression(s)](#break-expressions) may terminate, and must have type compatible with the value of the `break` expression(s).
ea8adc8c
XL
43
44## Predicate loops
45
8faf50e0
XL
46> **<sup>Syntax</sup>**\
47> _PredicateLoopExpression_ :\
ba9703b0 48> &nbsp;&nbsp; `while` [_Expression_]<sub>_except struct expression_</sub> [_BlockExpression_]
ff7c6d11 49
6a06907d
XL
50A `while` loop begins by evaluating the [boolean] loop conditional operand.
51If the loop conditional operand evaluates to `true`, the loop body block executes, then control returns to the loop conditional operand.
52If the loop conditional expression evaluates to `false`, the `while` expression completes.
ea8adc8c
XL
53
54An example:
55
56```rust
57let mut i = 0;
58
59while i < 10 {
60 println!("hello");
61 i = i + 1;
62}
63```
64
ff7c6d11
XL
65## Predicate pattern loops
66
8faf50e0
XL
67> **<sup>Syntax</sup>**\
68> [_PredicatePatternLoopExpression_] :\
136023e0 69> &nbsp;&nbsp; `while` `let` [_Pattern_] `=` [_Scrutinee_]<sub>_except lazy boolean operator expression_</sub>
8faf50e0 70> [_BlockExpression_]
ea8adc8c 71
136023e0 72
6a06907d
XL
73A `while let` loop is semantically similar to a `while` loop but in place of a condition expression it expects the keyword `let` followed by a pattern, an `=`, a [scrutinee] expression and a block expression.
74If the value of the scrutinee matches the pattern, the loop body block executes then control returns to the pattern matching statement.
75Otherwise, the while expression completes.
ea8adc8c
XL
76
77```rust
78let mut x = vec![1, 2, 3];
79
80while let Some(y) = x.pop() {
81 println!("y = {}", y);
82}
532ac7d7
XL
83
84while let _ = 5 {
85 println!("Irrefutable patterns are always true");
86 break;
87}
ea8adc8c
XL
88```
89
6a06907d 90A `while let` loop is equivalent to a `loop` expression containing a [`match` expression] as follows.
0bf4aa26 91
60c5eb7d 92<!-- ignore: expansion example -->
0bf4aa26 93```rust,ignore
532ac7d7 94'label: while let PATS = EXPR {
0bf4aa26
XL
95 /* loop body */
96}
97```
98
99is equivalent to
100
60c5eb7d 101<!-- ignore: expansion example -->
0bf4aa26
XL
102```rust,ignore
103'label: loop {
104 match EXPR {
532ac7d7 105 PATS => { /* loop body */ },
0bf4aa26
XL
106 _ => break,
107 }
108}
109```
110
6a06907d
XL
111Multiple patterns may be specified with the `|` operator.
112This has the same semantics as with `|` in `match` expressions:
532ac7d7
XL
113
114```rust
115let mut vals = vec![2, 3, 1, 2, 2];
116while let Some(v @ 1) | Some(v @ 2) = vals.pop() {
117 // Prints 2, 2, then 1
118 println!("{}", v);
119}
120```
121
ba9703b0
XL
122As is the case in [`if let` expressions], the scrutinee cannot be a [lazy boolean operator expression][_LazyBooleanOperatorExpression_].
123
ea8adc8c
XL
124## Iterator loops
125
8faf50e0
XL
126> **<sup>Syntax</sup>**\
127> _IteratorLoopExpression_ :\
ba9703b0 128> &nbsp;&nbsp; `for` [_Pattern_] `in` [_Expression_]<sub>_except struct expression_</sub>
ff7c6d11
XL
129> [_BlockExpression_]
130
6a06907d
XL
131A `for` expression is a syntactic construct for looping over elements provided by an implementation of `std::iter::IntoIterator`.
132If the iterator yields a value, that value is matched against the irrefutable pattern, the body of the loop is executed, and then control returns to the head of the `for` loop.
133If the iterator is empty, the `for` expression completes.
ea8adc8c
XL
134
135An example of a `for` loop over the contents of an array:
136
137```rust
138let v = &["apples", "cake", "coffee"];
139
140for text in v {
141 println!("I like {}.", text);
142}
143```
144
145An example of a for loop over a series of integers:
146
147```rust
148let mut sum = 0;
149for n in 1..11 {
150 sum += n;
151}
152assert_eq!(sum, 55);
153```
154
94222f64 155A `for` loop is equivalent to a `loop` expression containing a [`match` expression] as follows:
0bf4aa26 156
60c5eb7d 157<!-- ignore: expansion example -->
0bf4aa26
XL
158```rust,ignore
159'label: for PATTERN in iter_expr {
160 /* loop body */
161}
162```
163
164is equivalent to
165
60c5eb7d 166<!-- ignore: expansion example -->
0bf4aa26
XL
167```rust,ignore
168{
169 let result = match IntoIterator::into_iter(iter_expr) {
170 mut iter => 'label: loop {
171 let mut next;
172 match Iterator::next(&mut iter) {
173 Option::Some(val) => next = val,
174 Option::None => break,
175 };
f035d41b 176 let PATTERN = next;
0bf4aa26
XL
177 let () = { /* loop body */ };
178 },
179 };
180 result
181}
182```
183
6a06907d
XL
184`IntoIterator`, `Iterator`, and `Option` are always the standard library items here, not whatever those names resolve to in the current scope.
185The variable names `next`, `iter`, and `val` are for exposition only, they do not actually have names the user can type.
0bf4aa26 186
6a06907d
XL
187> **Note**: that the outer `match` is used to ensure that any [temporary values] in `iter_expr` don't get dropped before the loop is finished.
188> `next` is declared before being assigned because it results in types being inferred correctly more often.
0bf4aa26 189
ea8adc8c
XL
190## Loop labels
191
8faf50e0
XL
192> **<sup>Syntax</sup>**\
193> _LoopLabel_ :\
ff7c6d11
XL
194> &nbsp;&nbsp; [LIFETIME_OR_LABEL] `:`
195
6a06907d
XL
196A loop expression may optionally have a _label_. The label is written as a lifetime preceding the loop expression, as in `'foo: loop { break 'foo; }`, `'bar: while false {}`, `'humbug: for _ in 0..0 {}`.
197If a label is present, then labeled `break` and `continue` expressions nested within this loop may exit out of this loop or return control to its head.
198See [break expressions](#break-expressions) and [continue expressions](#continue-expressions).
ea8adc8c 199
2b03887a
FG
200Labels follow the hygiene and shadowing rules of local variables. For example, this code will print "outer loop":
201
202```rust
203'a: loop {
204 'a: loop {
205 break 'a;
206 }
207 print!("outer loop");
208 break 'a;
209}
210```
211
ea8adc8c
XL
212## `break` expressions
213
8faf50e0
XL
214> **<sup>Syntax</sup>**\
215> _BreakExpression_ :\
ff7c6d11
XL
216> &nbsp;&nbsp; `break` [LIFETIME_OR_LABEL]<sup>?</sup> [_Expression_]<sup>?</sup>
217
6a06907d 218When `break` is encountered, execution of the associated loop body is immediately terminated, for example:
ea8adc8c
XL
219
220```rust
221let mut last = 0;
222for x in 1..100 {
223 if x > 12 {
224 break;
225 }
226 last = x;
227}
228assert_eq!(last, 12);
229```
230
6a06907d
XL
231A `break` expression is normally associated with the innermost `loop`, `for` or `while` loop enclosing the `break` expression,
232but a [label](#loop-labels) can be used to specify which enclosing loop is affected.
233Example:
ea8adc8c
XL
234
235```rust
236'outer: loop {
237 while true {
238 break 'outer;
239 }
240}
241```
242
6a06907d 243A `break` expression is only permitted in the body of a loop, and has one of the forms `break`, `break 'label` or ([see below](#break-and-loop-values)) `break EXPR` or `break 'label EXPR`.
ea8adc8c 244
2b03887a
FG
245## Labelled block expressions
246
247> **<sup>Syntax</sup>**\
248> _LabelBlockExpression_ :\
249> &nbsp;&nbsp; [_BlockExpression_]
250
251Labelled block expressions are exactly like block expressions, except that they allow using `break` expressions within the block.
353b0b11
FG
252Unlike loops, `break` expressions within a labelled block expression *must* have a label (i.e. the label is not optional).
253Similarly, labelled block expressions *must* begin with a label.
254
255```rust
256# fn do_thing() {}
257# fn condition_not_met() -> bool { true }
258# fn do_next_thing() {}
259# fn do_last_thing() {}
260let result = 'block: {
261 do_thing();
262 if condition_not_met() {
263 break 'block 1;
264 }
265 do_next_thing();
266 if condition_not_met() {
267 break 'block 2;
268 }
269 do_last_thing();
270 3
271};
272```
2b03887a 273
ea8adc8c
XL
274## `continue` expressions
275
8faf50e0
XL
276> **<sup>Syntax</sup>**\
277> _ContinueExpression_ :\
ff7c6d11
XL
278> &nbsp;&nbsp; `continue` [LIFETIME_OR_LABEL]<sup>?</sup>
279
6a06907d
XL
280When `continue` is encountered, the current iteration of the associated loop body is immediately terminated, returning control to the loop *head*.
281In the case of a `while` loop, the head is the conditional expression controlling the loop.
282In the case of a `for` loop, the head is the call-expression controlling the loop.
ea8adc8c 283
6a06907d 284Like `break`, `continue` is normally associated with the innermost enclosing loop, but `continue 'label` may be used to specify the loop affected.
ea8adc8c
XL
285A `continue` expression is only permitted in the body of a loop.
286
287## `break` and loop values
288
6a06907d
XL
289When associated with a `loop`, a break expression may be used to return a value from that loop, via one of the forms `break EXPR` or `break 'label EXPR`, where `EXPR` is an expression whose result is returned from the `loop`.
290For example:
ea8adc8c
XL
291
292```rust
293let (mut a, mut b) = (1, 1);
294let result = loop {
295 if b > 10 {
296 break b;
297 }
298 let c = a + b;
299 a = b;
300 b = c;
301};
302// first number in Fibonacci sequence over 10:
303assert_eq!(result, 13);
304```
305
6a06907d
XL
306In the case a `loop` has an associated `break`, it is not considered diverging, and the `loop` must have a type compatible with each `break` expression.
307`break` without an expression is considered identical to `break` with expression `()`.
ff7c6d11 308
416331ca
XL
309[LIFETIME_OR_LABEL]: ../tokens.md#lifetimes-and-loop-labels
310[_BlockExpression_]: block-expr.md
e1599b0c 311[_Expression_]: ../expressions.md
416331ca 312[_Pattern_]: ../patterns.md
136023e0 313[_Scrutinee_]: match-expr.md
416331ca 314[`match` expression]: match-expr.md
6a06907d 315[boolean]: ../types/boolean.md
416331ca 316[scrutinee]: ../glossary.md#scrutinee
f9f354fc 317[temporary values]: ../expressions.md#temporaries
ba9703b0
XL
318[_LazyBooleanOperatorExpression_]: operator-expr.md#lazy-boolean-operators
319[`if let` expressions]: if-expr.md#if-let-expressions