auto merge of #15531 : steveklabnik/rust/guide_looping, r=brson
This commit is contained in:
commit
5cef16e9b3
1 changed files with 137 additions and 4 deletions
141
src/doc/guide.md
141
src/doc/guide.md
|
@ -1362,13 +1362,146 @@ string where we don't need to, but sometimes, it's a nice pattern.
|
|||
|
||||
## Looping
|
||||
|
||||
for
|
||||
Looping is the last basic construct that we haven't learned yet in Rust. Rust has
|
||||
two main looping constructs: `for` and `while`.
|
||||
|
||||
while
|
||||
### `for`
|
||||
|
||||
loop
|
||||
The `for` loop is used to loop a particular number of times. Rust's `for` loops
|
||||
work a bit differently than in other systems languages, however. Rust's `for`
|
||||
loop doesn't look like this C `for` loop:
|
||||
|
||||
break/continue
|
||||
```{ignore,c}
|
||||
for (x = 0; x < 10; x++) {
|
||||
printf( "%d\n", x );
|
||||
}
|
||||
```
|
||||
|
||||
It looks like this:
|
||||
|
||||
```{rust}
|
||||
for x in range(0i, 10i) {
|
||||
println!("{:d}", x);
|
||||
}
|
||||
```
|
||||
|
||||
In slightly more abstract terms,
|
||||
|
||||
```{ignore,notrust}
|
||||
for var in expression {
|
||||
code
|
||||
}
|
||||
```
|
||||
|
||||
The expression is an iterator, which we will discuss in more depth later in the
|
||||
guide. The iterator gives back a series of elements. Each element is one
|
||||
iteration of the loop. That value is then bound to the name `var`, which is
|
||||
valid for the loop body. Once the body is over, the next value is fetched from
|
||||
the iterator, and we loop another time. When there are no more values, the
|
||||
`for` loop is over.
|
||||
|
||||
In our example, the `range` function is a function, provided by Rust, that
|
||||
takes a start and an end position, and gives an iterator over those values. The
|
||||
upper bound is exclusive, though, so our loop will print `0` through `9`, not
|
||||
`10`.
|
||||
|
||||
Rust does not have the "C style" `for` loop on purpose. Manually controlling
|
||||
each element of the loop is complicated and error prone, even for experienced C
|
||||
developers. There's an old joke that goes, "There are two hard problems in
|
||||
computer science: naming things, cache invalidation, and off-by-one errors."
|
||||
The joke, of course, being that the setup says "two hard problems" but then
|
||||
lists three things. This happens quite a bit with "C style" `for` loops.
|
||||
|
||||
We'll talk more about `for` when we cover **vector**s, later in the Guide.
|
||||
|
||||
### `while`
|
||||
|
||||
The other kind of looping construct in Rust is the `while` loop. It looks like
|
||||
this:
|
||||
|
||||
```{rust}
|
||||
let mut x = 5u;
|
||||
let mut done = false;
|
||||
|
||||
while !done {
|
||||
x += x - 3;
|
||||
println!("{}", x);
|
||||
if x % 5 == 0 { done = true; }
|
||||
}
|
||||
```
|
||||
|
||||
`while` loops are the correct choice when you're not sure how many times
|
||||
you need to loop.
|
||||
|
||||
If you need an infinite loop, you may be tempted to write this:
|
||||
|
||||
```{rust,ignore}
|
||||
while true {
|
||||
```
|
||||
|
||||
Rust has a dedicated keyword, `loop`, to handle this case:
|
||||
|
||||
```{rust,ignore}
|
||||
loop {
|
||||
```
|
||||
|
||||
Rust's control-flow analysis treats this construct differently than a
|
||||
`while true`, since we know that it will always loop. The details of what
|
||||
that _means_ aren't super important to understand at this stage, but in
|
||||
general, the more information we can give to the compiler, the better it
|
||||
can do with safety and code generation. So you should always prefer
|
||||
`loop` when you plan to loop infinitely.
|
||||
|
||||
### Ending iteration early
|
||||
|
||||
Let's take a look at that `while` loop we had earlier:
|
||||
|
||||
```{rust}
|
||||
let mut x = 5u;
|
||||
let mut done = false;
|
||||
|
||||
while !done {
|
||||
x += x - 3;
|
||||
println!("{}", x);
|
||||
if x % 5 == 0 { done = true; }
|
||||
}
|
||||
```
|
||||
|
||||
We had to keep a dedicated `mut` boolean variable binding, `done`, to know
|
||||
when we should skip out of the loop. Rust has two keywords to help us with
|
||||
modifying iteration: `break` and `continue`.
|
||||
|
||||
In this case, we can write the loop in a better way with `break`:
|
||||
|
||||
```{rust}
|
||||
let mut x = 5u;
|
||||
|
||||
loop {
|
||||
x += x - 3;
|
||||
println!("{}", x);
|
||||
if x % 5 == 0 { break; }
|
||||
}
|
||||
```
|
||||
|
||||
We now loop forever with `loop`, and use `break` to break out early.
|
||||
|
||||
`continue` is similar, but instead of ending the loop, goes to the next
|
||||
iteration: This will only print the odd numbers:
|
||||
|
||||
```
|
||||
for x in range(0i, 10i) {
|
||||
if x % 2 == 0 { continue; }
|
||||
|
||||
println!("{:d}", x);
|
||||
}
|
||||
```
|
||||
|
||||
Both `continue` and `break` are valid in both kinds of loops.
|
||||
|
||||
We have now learned all of the most basic Rust concepts. We're ready to start
|
||||
building our guessing game, but we need to know how to do one last thing first:
|
||||
get input from the keyboard. You can't have a guessing game without the ability
|
||||
to guess!
|
||||
|
||||
## Guessing Game: complete
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue