]>
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. | |
ff7c6d11 | 22 | * A [`while let` expression](#predicate-pattern-loops) tests a refutable 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 |
13cf67c4 | 40 | has type [`!`](types/never.html). 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_ :\ | |
ff7c6d11 XL |
48 | > `while` [_Expression_]<sub>except struct expression</sub> [_BlockExpression_] |
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_] :\ | |
0bf4aa26 | 70 | > `while` `let` [_Pattern_] `=` [_Expression_]<sub>except struct 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 | |
74 | condition expression it expects the keyword `let` followed by a refutable | |
9fa01778 XL |
75 | pattern, an `=`, a [scrutinee] expression and a block expression. If the value of |
76 | the expression on the right hand side of the `=` matches the pattern, the loop | |
77 | body block executes then control returns to the pattern matching statement. | |
78 | Otherwise, the while expression 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 | } | |
86 | ``` | |
87 | ||
0bf4aa26 XL |
88 | A `while let` loop is equivalent to a `loop` expression containing a `match` |
89 | expression as follows. | |
90 | ||
91 | ```rust,ignore | |
92 | 'label: while let PAT = EXPR { | |
93 | /* loop body */ | |
94 | } | |
95 | ``` | |
96 | ||
97 | is equivalent to | |
98 | ||
99 | ```rust,ignore | |
100 | 'label: loop { | |
101 | match EXPR { | |
102 | PAT => { /* loop body */ }, | |
103 | _ => break, | |
104 | } | |
105 | } | |
106 | ``` | |
107 | ||
ea8adc8c XL |
108 | ## Iterator loops |
109 | ||
8faf50e0 XL |
110 | > **<sup>Syntax</sup>**\ |
111 | > _IteratorLoopExpression_ :\ | |
0bf4aa26 | 112 | > `for` [_Pattern_] `in` [_Expression_]<sub>except struct expression</sub> |
ff7c6d11 XL |
113 | > [_BlockExpression_] |
114 | ||
ea8adc8c XL |
115 | A `for` expression is a syntactic construct for looping over elements provided |
116 | by an implementation of `std::iter::IntoIterator`. If the iterator yields a | |
117 | value, that value is given the specified name and the body of the loop is | |
118 | executed, then control returns to the head of the `for` loop. If the iterator | |
119 | is empty, the `for` expression completes. | |
120 | ||
121 | An example of a `for` loop over the contents of an array: | |
122 | ||
123 | ```rust | |
124 | let v = &["apples", "cake", "coffee"]; | |
125 | ||
126 | for text in v { | |
127 | println!("I like {}.", text); | |
128 | } | |
129 | ``` | |
130 | ||
131 | An example of a for loop over a series of integers: | |
132 | ||
133 | ```rust | |
134 | let mut sum = 0; | |
135 | for n in 1..11 { | |
136 | sum += n; | |
137 | } | |
138 | assert_eq!(sum, 55); | |
139 | ``` | |
140 | ||
0bf4aa26 XL |
141 | A for loop is equivalent to the following block expression. |
142 | ||
143 | ```rust,ignore | |
144 | 'label: for PATTERN in iter_expr { | |
145 | /* loop body */ | |
146 | } | |
147 | ``` | |
148 | ||
149 | is equivalent to | |
150 | ||
151 | ```rust,ignore | |
152 | { | |
153 | let result = match IntoIterator::into_iter(iter_expr) { | |
154 | mut iter => 'label: loop { | |
155 | let mut next; | |
156 | match Iterator::next(&mut iter) { | |
157 | Option::Some(val) => next = val, | |
158 | Option::None => break, | |
159 | }; | |
160 | let PAT = next; | |
161 | let () = { /* loop body */ }; | |
162 | }, | |
163 | }; | |
164 | result | |
165 | } | |
166 | ``` | |
167 | ||
168 | `IntoIterator`, `Iterator` and `Option` are always the standard library items | |
169 | here, not whatever those names resolve to in the current scope. The variable | |
170 | names `next`, `iter` and `val` are for exposition only, they do not actually | |
171 | have names the user can type. | |
172 | ||
173 | > **Note**: that the outer `match` is used to ensure that any | |
174 | > [temporary values] in `iter_expr` don't get dropped before the loop is | |
175 | > finished. `next` is declared before being assigned because it results in | |
176 | > types being inferred correctly more often. | |
177 | ||
ea8adc8c XL |
178 | ## Loop labels |
179 | ||
8faf50e0 XL |
180 | > **<sup>Syntax</sup>**\ |
181 | > _LoopLabel_ :\ | |
ff7c6d11 XL |
182 | > [LIFETIME_OR_LABEL] `:` |
183 | ||
ea8adc8c XL |
184 | A loop expression may optionally have a _label_. The label is written as |
185 | a lifetime preceding the loop expression, as in `'foo: loop { break 'foo; }`, | |
186 | `'bar: while false {}`, `'humbug: for _ in 0..0 {}`. | |
187 | If a label is present, then labeled `break` and `continue` expressions nested | |
188 | within this loop may exit out of this loop or return control to its head. | |
189 | See [break expressions](#break-expressions) and [continue | |
190 | expressions](#continue-expressions). | |
191 | ||
192 | ## `break` expressions | |
193 | ||
8faf50e0 XL |
194 | > **<sup>Syntax</sup>**\ |
195 | > _BreakExpression_ :\ | |
ff7c6d11 XL |
196 | > `break` [LIFETIME_OR_LABEL]<sup>?</sup> [_Expression_]<sup>?</sup> |
197 | ||
ea8adc8c XL |
198 | When `break` is encountered, execution of the associated loop body is |
199 | immediately terminated, for example: | |
200 | ||
201 | ```rust | |
202 | let mut last = 0; | |
203 | for x in 1..100 { | |
204 | if x > 12 { | |
205 | break; | |
206 | } | |
207 | last = x; | |
208 | } | |
209 | assert_eq!(last, 12); | |
210 | ``` | |
211 | ||
212 | A `break` expression is normally associated with the innermost `loop`, `for` or | |
213 | `while` loop enclosing the `break` expression, but a [label](#loop-labels) can | |
214 | be used to specify which enclosing loop is affected. Example: | |
215 | ||
216 | ```rust | |
217 | 'outer: loop { | |
218 | while true { | |
219 | break 'outer; | |
220 | } | |
221 | } | |
222 | ``` | |
223 | ||
224 | A `break` expression is only permitted in the body of a loop, and has one of | |
225 | the forms `break`, `break 'label` or ([see below](#break-and-loop-values)) | |
226 | `break EXPR` or `break 'label EXPR`. | |
227 | ||
228 | ## `continue` expressions | |
229 | ||
8faf50e0 XL |
230 | > **<sup>Syntax</sup>**\ |
231 | > _ContinueExpression_ :\ | |
ff7c6d11 XL |
232 | > `continue` [LIFETIME_OR_LABEL]<sup>?</sup> |
233 | ||
ea8adc8c XL |
234 | When `continue` is encountered, the current iteration of the associated loop |
235 | body is immediately terminated, returning control to the loop *head*. In | |
236 | the case of a `while` loop, the head is the conditional expression controlling | |
237 | the loop. In the case of a `for` loop, the head is the call-expression | |
238 | controlling the loop. | |
239 | ||
240 | Like `break`, `continue` is normally associated with the innermost enclosing | |
241 | loop, but `continue 'label` may be used to specify the loop affected. | |
242 | A `continue` expression is only permitted in the body of a loop. | |
243 | ||
244 | ## `break` and loop values | |
245 | ||
246 | When associated with a `loop`, a break expression may be used to return a value | |
247 | from that loop, via one of the forms `break EXPR` or `break 'label EXPR`, where | |
248 | `EXPR` is an expression whose result is returned from the `loop`. For example: | |
249 | ||
250 | ```rust | |
251 | let (mut a, mut b) = (1, 1); | |
252 | let result = loop { | |
253 | if b > 10 { | |
254 | break b; | |
255 | } | |
256 | let c = a + b; | |
257 | a = b; | |
258 | b = c; | |
259 | }; | |
260 | // first number in Fibonacci sequence over 10: | |
261 | assert_eq!(result, 13); | |
262 | ``` | |
263 | ||
264 | In the case a `loop` has an associated `break`, it is not considered diverging, | |
265 | and the `loop` must have a type compatible with each `break` expression. | |
266 | `break` without an expression is considered identical to `break` with | |
267 | expression `()`. | |
ff7c6d11 XL |
268 | |
269 | [IDENTIFIER]: identifiers.html | |
0bf4aa26 | 270 | [temporary values]: expressions.html#temporary-lifetimes |
ff7c6d11 XL |
271 | |
272 | [_Expression_]: expressions.html | |
273 | [_BlockExpression_]: expressions/block-expr.html | |
0bf4aa26 | 274 | [_Pattern_]: patterns.html |
ff7c6d11 | 275 | |
0531ce1d | 276 | [LIFETIME_OR_LABEL]: tokens.html#lifetimes-and-loop-labels |
9fa01778 XL |
277 | |
278 | [scrutinee]: glossary.html#scrutinee |