]>
Commit | Line | Data |
---|---|---|
c1a9b12d SL |
1 | % Loops |
2 | ||
3 | Rust currently provides three approaches to performing some kind of iterative activity. They are: `loop`, `while` and `for`. Each approach has its own set of uses. | |
4 | ||
5 | ## loop | |
6 | ||
7 | The infinite `loop` is the simplest form of loop available in Rust. Using the keyword `loop`, Rust provides a way to loop indefinitely until some terminating statement is reached. Rust's infinite `loop`s look like this: | |
8 | ||
9 | ```rust,ignore | |
10 | loop { | |
11 | println!("Loop forever!"); | |
12 | } | |
13 | ``` | |
14 | ||
15 | ## while | |
16 | ||
17 | Rust also has a `while` loop. It looks like this: | |
18 | ||
19 | ```rust | |
20 | let mut x = 5; // mut x: i32 | |
21 | let mut done = false; // mut done: bool | |
22 | ||
23 | while !done { | |
24 | x += x - 3; | |
25 | ||
26 | println!("{}", x); | |
27 | ||
28 | if x % 5 == 0 { | |
29 | done = true; | |
30 | } | |
31 | } | |
32 | ``` | |
33 | ||
34 | `while` loops are the correct choice when you’re not sure how many times | |
35 | you need to loop. | |
36 | ||
37 | If you need an infinite loop, you may be tempted to write this: | |
38 | ||
39 | ```rust,ignore | |
40 | while true { | |
41 | ``` | |
42 | ||
43 | However, `loop` is far better suited to handle this case: | |
44 | ||
45 | ```rust,ignore | |
46 | loop { | |
47 | ``` | |
48 | ||
49 | Rust’s control-flow analysis treats this construct differently than a `while | |
50 | true`, since we know that it will always loop. In general, the more information | |
51 | we can give to the compiler, the better it can do with safety and code | |
52 | generation, so you should always prefer `loop` when you plan to loop | |
53 | infinitely. | |
54 | ||
55 | ## for | |
56 | ||
57 | The `for` loop is used to loop a particular number of times. Rust’s `for` loops | |
58 | work a bit differently than in other systems languages, however. Rust’s `for` | |
59 | loop doesn’t look like this “C-style” `for` loop: | |
60 | ||
61 | ```c | |
62 | for (x = 0; x < 10; x++) { | |
63 | printf( "%d\n", x ); | |
64 | } | |
65 | ``` | |
66 | ||
67 | Instead, it looks like this: | |
68 | ||
69 | ```rust | |
70 | for x in 0..10 { | |
71 | println!("{}", x); // x: i32 | |
72 | } | |
73 | ``` | |
74 | ||
75 | In slightly more abstract terms, | |
76 | ||
a7813a04 | 77 | ```rust,ignore |
c1a9b12d SL |
78 | for var in expression { |
79 | code | |
80 | } | |
81 | ``` | |
82 | ||
92a42be0 SL |
83 | The expression is an item that can be converted into an [iterator] using |
84 | [`IntoIterator`]. The iterator gives back a series of elements. Each element is | |
85 | one iteration of the loop. That value is then bound to the name `var`, which is | |
86 | valid for the loop body. Once the body is over, the next value is fetched from | |
87 | the iterator, and we loop another time. When there are no more values, the `for` | |
88 | loop is over. | |
c1a9b12d SL |
89 | |
90 | [iterator]: iterators.html | |
92a42be0 | 91 | [`IntoIterator`]: ../std/iter/trait.IntoIterator.html |
c1a9b12d SL |
92 | |
93 | In our example, `0..10` is an expression that takes a start and an end position, | |
94 | and gives an iterator over those values. The upper bound is exclusive, though, | |
95 | so our loop will print `0` through `9`, not `10`. | |
96 | ||
97 | Rust does not have the “C-style” `for` loop on purpose. Manually controlling | |
98 | each element of the loop is complicated and error prone, even for experienced C | |
99 | developers. | |
100 | ||
101 | ### Enumerate | |
102 | ||
103 | When you need to keep track of how many times you already looped, you can use the `.enumerate()` function. | |
104 | ||
105 | #### On ranges: | |
106 | ||
107 | ```rust | |
5bcae85e SL |
108 | for (index, value) in (5..10).enumerate() { |
109 | println!("index = {} and value = {}", index, value); | |
c1a9b12d SL |
110 | } |
111 | ``` | |
112 | ||
113 | Outputs: | |
114 | ||
115 | ```text | |
5bcae85e SL |
116 | index = 0 and value = 5 |
117 | index = 1 and value = 6 | |
118 | index = 2 and value = 7 | |
119 | index = 3 and value = 8 | |
120 | index = 4 and value = 9 | |
c1a9b12d SL |
121 | ``` |
122 | ||
123 | Don't forget to add the parentheses around the range. | |
124 | ||
125 | #### On iterators: | |
126 | ||
127 | ```rust | |
7453a54e SL |
128 | let lines = "hello\nworld".lines(); |
129 | ||
c1a9b12d SL |
130 | for (linenumber, line) in lines.enumerate() { |
131 | println!("{}: {}", linenumber, line); | |
132 | } | |
133 | ``` | |
134 | ||
135 | Outputs: | |
136 | ||
137 | ```text | |
7453a54e SL |
138 | 0: hello |
139 | 1: world | |
c1a9b12d SL |
140 | ``` |
141 | ||
142 | ## Ending iteration early | |
143 | ||
144 | Let’s take a look at that `while` loop we had earlier: | |
145 | ||
146 | ```rust | |
147 | let mut x = 5; | |
148 | let mut done = false; | |
149 | ||
150 | while !done { | |
151 | x += x - 3; | |
152 | ||
153 | println!("{}", x); | |
154 | ||
155 | if x % 5 == 0 { | |
156 | done = true; | |
157 | } | |
158 | } | |
159 | ``` | |
160 | ||
161 | We had to keep a dedicated `mut` boolean variable binding, `done`, to know | |
162 | when we should exit out of the loop. Rust has two keywords to help us with | |
163 | modifying iteration: `break` and `continue`. | |
164 | ||
165 | In this case, we can write the loop in a better way with `break`: | |
166 | ||
167 | ```rust | |
168 | let mut x = 5; | |
169 | ||
170 | loop { | |
171 | x += x - 3; | |
172 | ||
173 | println!("{}", x); | |
174 | ||
175 | if x % 5 == 0 { break; } | |
176 | } | |
177 | ``` | |
178 | ||
179 | We now loop forever with `loop` and use `break` to break out early. Issuing an explicit `return` statement will also serve to terminate the loop early. | |
180 | ||
3157f602 | 181 | `continue` is similar, but instead of ending the loop, it goes to the next |
c1a9b12d SL |
182 | iteration. This will only print the odd numbers: |
183 | ||
184 | ```rust | |
185 | for x in 0..10 { | |
186 | if x % 2 == 0 { continue; } | |
187 | ||
188 | println!("{}", x); | |
189 | } | |
190 | ``` | |
191 | ||
192 | ## Loop labels | |
193 | ||
194 | You may also encounter situations where you have nested loops and need to | |
195 | specify which one your `break` or `continue` statement is for. Like most | |
196 | other languages, by default a `break` or `continue` will apply to innermost | |
7453a54e | 197 | loop. In a situation where you would like to `break` or `continue` for one |
c1a9b12d SL |
198 | of the outer loops, you can use labels to specify which loop the `break` or |
199 | `continue` statement applies to. This will only print when both `x` and `y` are | |
200 | odd: | |
201 | ||
202 | ```rust | |
203 | 'outer: for x in 0..10 { | |
204 | 'inner: for y in 0..10 { | |
205 | if x % 2 == 0 { continue 'outer; } // continues the loop over x | |
206 | if y % 2 == 0 { continue 'inner; } // continues the loop over y | |
207 | println!("x: {}, y: {}", x, y); | |
208 | } | |
209 | } | |
210 | ``` |