You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: src/ch03-07-control-flow.md
+53-87Lines changed: 53 additions & 87 deletions
Original file line number
Diff line number
Diff line change
@@ -1,9 +1,12 @@
1
1
## Control Flow
2
2
3
-
<!--Au: Can you please add a general intro for control flow and the following
4
-
if and loops sections here? /Liz -->
3
+
Deciding whether or not to run some code depending on if a condition is true,
4
+
or deciding to run some code repeatedly while a condition is true, are basic
5
+
building blocks in most programming languages. The most common constructs that
6
+
let us control the flow of execution of our Rust code are `if` expressions and
7
+
loops.
5
8
6
-
### `if`Statements
9
+
### `if`Expressions
7
10
8
11
> Two roads diverged in a yellow wood,
9
12
> And sorry I could not travel both
@@ -13,10 +16,9 @@ if and loops sections here? /Liz -->
13
16
>
14
17
> - Robert Frost, “The Road Not Taken”
15
18
16
-
In Rust, as in most programming languages, an `if` expression allows us to
17
-
branch our code depending on conditions. We provide a condition, and then say,
18
-
`if` this condition is met, then run this block of code. If the condition is
19
-
not met, do not run this block of code.
19
+
An `if` expression allows us to branch our code depending on conditions. We
20
+
provide a condition and then say, "If this condition is met, then run this
21
+
block of code. If the condition is not met, do not run this block of code."
20
22
21
23
Let’s make a new project to explore `if`. Navigate to your projects directory,
22
24
and use Cargo to make a new project called `branches`:
@@ -40,7 +42,7 @@ fn main() {
40
42
```
41
43
42
44
The `condition` variable is a boolean; here, it's set to true. All `if`
43
-
statements start with `if`, which is followed by a condition. The block of code
45
+
expressions start with `if`, which is followed by a condition. The block of code
44
46
we want to execute if the condition is true goes immediately after the
45
47
condition, inside curly braces. These blocks are sometimes called ‘arms’.
46
48
@@ -98,17 +100,6 @@ condition was false
98
100
This time, because `condition` was false and we have an `else` block, the
99
101
`else` block was executed.
100
102
101
-
<!-- TR: Do these examples make sense this way round, or would it be clearer to
102
-
give the example using the if statement alone, and then the example giving the
103
-
if and else statements? /Liz -->
104
-
<!-- I think having just `if` first, then `if`+`else` would be better... this
105
-
section also reads pretty repetitively to me, which I think would be great if
106
-
the target audience was people who hadn't programmed before, but I think people
107
-
who have used at least one other programming language should be pretty familiar
108
-
with the concept of how an `if` statement works and just need to know the
109
-
particulars of the syntax in Rust. I've given rearranging this section a try,
110
-
see what you think! /Carol -->
111
-
112
103
It’s also worth noting that `condition` here _must_ be a `bool`. To see what
113
104
happens if the condition isn't a `bool`, try running this code:
114
105
@@ -142,10 +133,19 @@ Could not compile `branches`.
142
133
The error tells us that Rust expected a `bool`, but got an integer. Rust will
143
134
not automatically try to convert non-boolean types to a boolean here, unlike
144
135
languages like Ruby or JavaScript. We must be explicit and always give `if` a
145
-
`boolean` as its condition.
136
+
`boolean` as its condition. If your intention is for the `if` code block to be run if a number is not equal to `0`, for example, we would change the `if` expression to read:
137
+
138
+
```rust
139
+
fn main() {
140
+
let condition = 5;
141
+
142
+
if condition != 0 {
143
+
println!("condition was something other than zero");
144
+
}
145
+
}
146
+
```
146
147
147
-
<!--TR: What must we be explicit about? /Liz -->
148
-
<!-- Expanded a bit /Carol -->
148
+
Running this will print "condition was something other than zero".
149
149
150
150
#### Multiple Conditions with `else if`
151
151
@@ -218,9 +218,9 @@ The value of number is: 5
218
218
Remember, blocks of code evaluate to the last expression in them, and numbers
219
219
by themselves are also expressions. In this case, the value of the whole `if`
220
220
expression depends on which block of code executes. This means that the value
221
-
in both arms of the `if` must be the same type; in the previous example, they
222
-
were both `i32` integers. But what happens if the types are mismatched, as in
223
-
the following example?
221
+
that results from both arms of the `if` must be the same type; in the previous
222
+
example, they were both `i32` integers. But what happens if the types are
223
+
mismatched, as in the following example?
224
224
225
225
```rust,ignore
226
226
fn main() {
@@ -236,9 +236,9 @@ fn main() {
236
236
}
237
237
```
238
238
239
-
The expression in one block of the `if` statement, is an integer and the
240
-
expresion in the other block is a string. If we try to run this, we’ll get an
241
-
error:
239
+
The expression in the `if` block is an integer and the expresion in the `else`
240
+
block is a string. This can’t work, because variable bindings must have a
241
+
single type. If we try to run this, we’ll get an error:
The `if` and `else` arms have value types that are incompatible, and Rust tells
261
-
us exactly where to find the problem in our program. This can’t work, because
262
-
variable bindings must have a single type.
261
+
us exactly where to find the problem in our program.
263
262
264
263
### Repetition with Loops
265
264
@@ -279,12 +278,8 @@ in.
279
278
280
279
#### Repeating Code with `loop`
281
280
282
-
<!--TR: By "keyword" do we just mean a statement or function embedded in the
283
-
Rust language, that can't be changed? /Liz -->
284
-
<!-- Yup, see the keyword section I added at the beginning. /Carol -->
285
-
286
281
The `loop` keyword tells Rust to execute a block of code over and over again
287
-
forever, or until we explicitly tell it to stop.
282
+
forever or until we explicitly tell it to stop.
288
283
289
284
For an example, change the *src/main.rs* file in your *loops* directory to look
290
285
like this:
@@ -311,15 +306,12 @@ again!
311
306
again!
312
307
^Cagain!
313
308
```
314
-
<!-- TR: Is this correct, it will print "again" one last time after hitting
315
-
ctrl c? /Liz -->
316
-
<!-- Sometimes it will-- it depends on where in the execution the program is at
317
-
the exact instant you hit control-c. /Carol -->
318
309
319
-
That `^C` there is where I hit `control-c`. Fortunately, Rust provides another,
320
-
more reliable way to break out of a loop. We can place the `break` keyword
321
-
within the loop to tell the program when to stop executing the loop. Try this
322
-
version of the program out:
310
+
That `^C` there is where I hit `control-c`. You may or may not see "again!" printed after the `^C`, depending on where the code was in the loop when it received the signal to halt.
311
+
312
+
Fortunately, Rust provides another, more reliable way to break out of a loop.
313
+
We can place the `break` keyword within the loop to tell the program when to
314
+
stop executing the loop. Try this version of the program out:
323
315
324
316
```rust
325
317
fn main() {
@@ -384,24 +376,10 @@ This program loops three times, counting down each time. Finally, after the
384
376
loop, it prints another message, then exits.
385
377
386
378
The core of this example is in the combination of `loop`, `if`, `else`, and
387
-
`break`.
388
-
389
-
<!--```rust,ignore
390
-
loop {
391
-
if number != 0 {
392
-
// do stuff
393
-
} else {
394
-
break;
395
-
}
396
-
```-->
397
-
<!--TR/au: I'm not sure we need to repeat this so close to its first appearance
398
-
/Liz -->
399
-
<!-- Agreed /Carol -->
400
-
401
-
We want to `loop`, but only while some sort of condition is true. As soon as it
402
-
isn't, we want to `break` out of the loop. This pattern is so common that Rust
403
-
has a more efficient language construct for it, called a `while` loop. Here's
404
-
the same example, but using `while` instead:
379
+
`break`. We want to `loop`, but only while some sort of condition is true. As
380
+
soon as it isn't, we want to `break` out of the loop. This pattern is so common
381
+
that Rust has a more efficient language construct for it, called a `while`
382
+
loop. Here's the same example, but using `while` instead:
405
383
406
384
```rust
407
385
fn main() {
@@ -438,10 +416,6 @@ fn main() {
438
416
}
439
417
```
440
418
441
-
<!-- I changed the numbers in the array to be 10, etc just to avoid any
442
-
possible confusion with 0-based and 1-based array indexing that some people
443
-
might have. /Carol -->
444
-
445
419
Here, we're counting up through the elements in the array. We start at index 0,
446
420
then loop until we hit the final index of our array (that is, when `index < 5`
447
421
is no longer true). Running this will print out every element of the array:
@@ -466,8 +440,8 @@ getting the index length incorrect. It's also slow, as the compiler needs to
466
440
perform the conditional check on every element on every iteration through the
467
441
loop.
468
442
469
-
As a more efficient alternative, we can use a `for` loop. A `for` loop looks
470
-
something like this:
443
+
As a more efficient alternative, we can use a `for` loop and execute some code
444
+
for each item in a collection. A `for` loop looks like this:
471
445
472
446
```rust
473
447
fn main() {
@@ -479,25 +453,17 @@ fn main() {
479
453
}
480
454
```
481
455
482
-
** NOTE: see [https://github.com/rust-lang/rust/issues/25725#issuecomment-166365658](https://github.com/rust-lang/rust/issues/25725#issuecomment-166365658), we may want to change this **
483
-
484
-
485
-
If we run this, we'll see the same output as the previous example.
486
-
487
-
<!--- Perhaps explain the difference, and how this handles the same operations
488
-
differently to while -->
489
-
490
-
<!-- Steve - so this needs wrapping up, and the chapter needs a general summary
491
-
of some sort. Does this need to waitfor long? -->
492
-
493
-
** I'm going to leave it at this for now until we decide how we want to do it**
456
+
If we run this, we'll see the same output as the previous example. Importantly,
457
+
though, we've now increased the safety of our code and eliminated the chance of
458
+
bugs resulting from going beyond the end of the array or not going far enough
459
+
and missing some items.
494
460
495
-
<!-- Au/TR Has this issue been resolved? We'll need a chapter wrap up, do we
496
-
need to come back to this at a later date? /Liz -->
461
+
For example, in the previous code that uses the `while` loop, if we removed an
462
+
item from the `a` array but forgot to update the condition to be `while index <
463
+
4`, our code would panic. Using the `for` loop means we would not need to
464
+
remember to change any other code if we changed the the number of values in the
465
+
array.
497
466
498
-
<!-- The issue has not been resolved... but I think it's ok to gloss over the
499
-
details a bit, or point to the chapters where method syntax or vecs will be
500
-
discussed? There are other issues that people will run into pretty quickly if
501
-
they try to actually use arrays at this point, such as the fact that they have
502
-
to be a fixed size known at compile time, so it's not like someone would be
503
-
able to put down the book at this point and be productive in Rust. /Carol -->
467
+
If you're wondering about the `.iter()` code in this example, keep reading! We
468
+
will cover method syntax generally in Chapter XX and iterators specifically in
469
+
Chapter XX. For now, though, let's get into the concept of ownership.
0 commit comments