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