]>
Commit | Line | Data |
---|---|---|
2b03887a | 1 | # Loops and other breakable expressions |
ea8adc8c | 2 | |
8faf50e0 XL |
3 | > **<sup>Syntax</sup>**\ |
4 | > _LoopExpression_ :\ | |
5 | > [_LoopLabel_]<sup>?</sup> (\ | |
6 | > [_InfiniteLoopExpression_]\ | |
7 | > | [_PredicateLoopExpression_]\ | |
8 | > | [_PredicatePatternLoopExpression_]\ | |
9 | > | [_IteratorLoopExpression_]\ | |
2b03887a | 10 | > | [_LabelBlockExpression_]\ |
8faf50e0 | 11 | > ) |
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 | 20 | Rust 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 |
28 | All five types of loop support [`break` expressions](#break-expressions), and [labels](#loop-labels). |
29 | All except labelled block expressions support [`continue` expressions](#continue-expressions). | |
30 | Only `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 | > `loop` [_BlockExpression_] |
37 | ||
ea8adc8c XL |
38 | A `loop` expression repeats execution of its body continuously: |
39 | `loop { println!("I live."); }`. | |
40 | ||
6a06907d XL |
41 | A `loop` expression without an associated `break` expression is diverging and has type [`!`](../types/never.md). |
42 | A `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 | > `while` [_Expression_]<sub>_except struct expression_</sub> [_BlockExpression_] |
ff7c6d11 | 49 | |
6a06907d XL |
50 | A `while` loop begins by evaluating the [boolean] loop conditional operand. |
51 | If the loop conditional operand evaluates to `true`, the loop body block executes, then control returns to the loop conditional operand. | |
52 | If the loop conditional expression evaluates to `false`, the `while` expression completes. | |
ea8adc8c XL |
53 | |
54 | An example: | |
55 | ||
56 | ```rust | |
57 | let mut i = 0; | |
58 | ||
59 | while 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 | > `while` `let` [_Pattern_] `=` [_Scrutinee_]<sub>_except lazy boolean operator expression_</sub> |
8faf50e0 | 70 | > [_BlockExpression_] |
ea8adc8c | 71 | |
136023e0 | 72 | |
6a06907d XL |
73 | A `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. |
74 | If the value of the scrutinee matches the pattern, the loop body block executes then control returns to the pattern matching statement. | |
75 | Otherwise, the while expression completes. | |
ea8adc8c XL |
76 | |
77 | ```rust | |
78 | let mut x = vec![1, 2, 3]; | |
79 | ||
80 | while let Some(y) = x.pop() { | |
81 | println!("y = {}", y); | |
82 | } | |
532ac7d7 XL |
83 | |
84 | while let _ = 5 { | |
85 | println!("Irrefutable patterns are always true"); | |
86 | break; | |
87 | } | |
ea8adc8c XL |
88 | ``` |
89 | ||
6a06907d | 90 | A `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 | ||
99 | is 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 |
111 | Multiple patterns may be specified with the `|` operator. |
112 | This has the same semantics as with `|` in `match` expressions: | |
532ac7d7 XL |
113 | |
114 | ```rust | |
115 | let mut vals = vec![2, 3, 1, 2, 2]; | |
116 | while let Some(v @ 1) | Some(v @ 2) = vals.pop() { | |
117 | // Prints 2, 2, then 1 | |
118 | println!("{}", v); | |
119 | } | |
120 | ``` | |
121 | ||
ba9703b0 XL |
122 | As 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 | > `for` [_Pattern_] `in` [_Expression_]<sub>_except struct expression_</sub> |
ff7c6d11 XL |
129 | > [_BlockExpression_] |
130 | ||
6a06907d XL |
131 | A `for` expression is a syntactic construct for looping over elements provided by an implementation of `std::iter::IntoIterator`. |
132 | If 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. | |
133 | If the iterator is empty, the `for` expression completes. | |
ea8adc8c XL |
134 | |
135 | An example of a `for` loop over the contents of an array: | |
136 | ||
137 | ```rust | |
138 | let v = &["apples", "cake", "coffee"]; | |
139 | ||
140 | for text in v { | |
141 | println!("I like {}.", text); | |
142 | } | |
143 | ``` | |
144 | ||
145 | An example of a for loop over a series of integers: | |
146 | ||
147 | ```rust | |
148 | let mut sum = 0; | |
149 | for n in 1..11 { | |
150 | sum += n; | |
151 | } | |
152 | assert_eq!(sum, 55); | |
153 | ``` | |
154 | ||
94222f64 | 155 | A `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 | ||
164 | is 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. |
185 | The 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 | > [LIFETIME_OR_LABEL] `:` |
195 | ||
6a06907d XL |
196 | A 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 {}`. |
197 | If 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. | |
198 | See [break expressions](#break-expressions) and [continue expressions](#continue-expressions). | |
ea8adc8c | 199 | |
2b03887a FG |
200 | Labels 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 | > `break` [LIFETIME_OR_LABEL]<sup>?</sup> [_Expression_]<sup>?</sup> |
217 | ||
6a06907d | 218 | When `break` is encountered, execution of the associated loop body is immediately terminated, for example: |
ea8adc8c XL |
219 | |
220 | ```rust | |
221 | let mut last = 0; | |
222 | for x in 1..100 { | |
223 | if x > 12 { | |
224 | break; | |
225 | } | |
226 | last = x; | |
227 | } | |
228 | assert_eq!(last, 12); | |
229 | ``` | |
230 | ||
6a06907d XL |
231 | A `break` expression is normally associated with the innermost `loop`, `for` or `while` loop enclosing the `break` expression, |
232 | but a [label](#loop-labels) can be used to specify which enclosing loop is affected. | |
233 | Example: | |
ea8adc8c XL |
234 | |
235 | ```rust | |
236 | 'outer: loop { | |
237 | while true { | |
238 | break 'outer; | |
239 | } | |
240 | } | |
241 | ``` | |
242 | ||
6a06907d | 243 | A `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 | > [_BlockExpression_] | |
250 | ||
251 | Labelled block expressions are exactly like block expressions, except that they allow using `break` expressions within the block. | |
353b0b11 FG |
252 | Unlike loops, `break` expressions within a labelled block expression *must* have a label (i.e. the label is not optional). |
253 | Similarly, 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() {} | |
260 | let 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 | > `continue` [LIFETIME_OR_LABEL]<sup>?</sup> |
279 | ||
6a06907d XL |
280 | When `continue` is encountered, the current iteration of the associated loop body is immediately terminated, returning control to the loop *head*. |
281 | In the case of a `while` loop, the head is the conditional expression controlling the loop. | |
282 | In the case of a `for` loop, the head is the call-expression controlling the loop. | |
ea8adc8c | 283 | |
6a06907d | 284 | Like `break`, `continue` is normally associated with the innermost enclosing loop, but `continue 'label` may be used to specify the loop affected. |
ea8adc8c XL |
285 | A `continue` expression is only permitted in the body of a loop. |
286 | ||
287 | ## `break` and loop values | |
288 | ||
6a06907d XL |
289 | When 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`. |
290 | For example: | |
ea8adc8c XL |
291 | |
292 | ```rust | |
293 | let (mut a, mut b) = (1, 1); | |
294 | let 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: | |
303 | assert_eq!(result, 13); | |
304 | ``` | |
305 | ||
6a06907d XL |
306 | In 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 |