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