mirror of
https://github.com/LCTT/TranslateProject.git
synced 2025-01-04 22:00:34 +08:00
352 lines
10 KiB
Markdown
352 lines
10 KiB
Markdown
[#]: subject: "Rust Basics Series #7: Using Loops in Rust"
|
|
[#]: via: "https://itsfoss.com/rust-loops/"
|
|
[#]: author: "Pratham Patel https://itsfoss.com/author/pratham/"
|
|
[#]: collector: "lkxed"
|
|
[#]: translator: " "
|
|
[#]: reviewer: " "
|
|
[#]: publisher: " "
|
|
[#]: url: " "
|
|
|
|
Rust Basics Series #7: Using Loops in Rust
|
|
======
|
|
|
|
In the [previous article][1] of the Rust series, I went over the use of if and else keywords to handle the control flow of your Rust program.
|
|
|
|
That is one way of handling the control flow of your program. The other way you can do this is by using loops. So let us look at loops in this follow-up article.
|
|
|
|
### Loops available in Rust
|
|
|
|
The Rust programming language has three different loops based on what you want to achieve and what is available:
|
|
|
|
- for
|
|
- while
|
|
- loop
|
|
|
|
I presume that you are familiar with `for` and `while` but `loop` might be new here. Let's start with familiar concepts first.
|
|
|
|
### The for loop
|
|
|
|
The `for` loop is primarily used to iterate over something called an iterator.
|
|
|
|
This iterator can be made from anything, from an array, a vector (will be covered soon!), a range of values, or anything custom. The sky is the limit here.
|
|
|
|
Let us look at the syntax of the `for` loop.
|
|
|
|
```
|
|
for iterating_variable in iterator {
|
|
<statement(s)>;
|
|
}
|
|
```
|
|
|
|
The `iterating_variable` is more generally known as `i` in most other programming language tutorials ;)
|
|
|
|
And an `iterator`, as I said, can be really anything that tells what the next value is, if any.
|
|
|
|
Let's understand this using a program.
|
|
|
|
```
|
|
fn main() {
|
|
let my_arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
|
|
|
|
println!("iteration over an array");
|
|
for element in my_arr {
|
|
println!("{}", element);
|
|
}
|
|
|
|
println!("\niteration over a real iterator");
|
|
for element in my_arr.iter() {
|
|
println!("{}", element);
|
|
}
|
|
|
|
println!("\nPython-style range");
|
|
for element in 0..10 {
|
|
println!("{}", element);
|
|
}
|
|
}
|
|
```
|
|
|
|
Here, I have declared an array that holds 10 numbers, from 0 to 9. On the `for` loop that is on line 5, I simply specify this array as the iterator and Rust automatically handles iteration over all the elements of this array for me. No fancy `my_arr[i]` magic is needed.
|
|
|
|
But on line 10, I call the `.iter()` function on the array. This is an explicit mention of getting an iterator based on the values that `my_arr` consists of. The only difference between this loop and the loop on line 5 is that here you are being explicit by calling the `.iter()` function on the array.
|
|
|
|
Calling the `.iter()` function on a data type, _in this context,_ isn't strictly necessary. Since this is an array, which is a data type provided by the language itself, Rust already knows how to handle it. But you _will_ need it with custom data types.
|
|
|
|
Finally, on line 15, we have a for loop that loops over a range. Well sort of. If you look closely, this range will look very similar to the Slice "type". Rust knows about this too and handles iteration _for_ you (haha, get it?).
|
|
|
|
The output looks like following:
|
|
|
|
```
|
|
iteration over an array
|
|
0
|
|
1
|
|
2
|
|
3
|
|
4
|
|
5
|
|
6
|
|
7
|
|
8
|
|
9
|
|
|
|
iteration over a real iterator
|
|
0
|
|
1
|
|
2
|
|
3
|
|
4
|
|
5
|
|
6
|
|
7
|
|
8
|
|
9
|
|
|
|
Python-style range
|
|
0
|
|
1
|
|
2
|
|
3
|
|
4
|
|
5
|
|
6
|
|
7
|
|
8
|
|
9
|
|
```
|
|
|
|
### The while loop
|
|
|
|
The `while` loop can be thought to be very similar to an `if` conditional statement. With the `if` statement, provided that the user-provided condition evaluates to `true`, the code in the `if` statement's body is executed _once_.
|
|
|
|
But with the `while` loop, if the condition evaluates to `true`, the loop starts looping over the loop body. The loop will continue its iteration as long as the condition keeps on evaulating to `true`.
|
|
|
|
The `while` loop stops only when the loop has completed the execution of all statements in the current iteration and upon checking the condition, it evaluates to `false`.
|
|
|
|
Let's look at the syntax of a while loop...
|
|
|
|
```
|
|
while condition {
|
|
<statement(s)>;
|
|
}
|
|
```
|
|
|
|
See? Very similar to an `if` conditional statement! No `else` blocks though ;)
|
|
|
|
Let's look at a program to understand this better.
|
|
|
|
```
|
|
fn main() {
|
|
let mut var = 0;
|
|
|
|
while var < 3 {
|
|
println!("{var}");
|
|
var += 1;
|
|
}
|
|
}
|
|
```
|
|
|
|
I have a mutable variable, `var`, with an initial value of 0. The `while` loop will loop as long as the value stored in the mutable variable `var` is less than 3.
|
|
|
|
Inside the loop, `var`'s value gets printed and later on, its value gets incremented by 1.
|
|
|
|
Below is the output of the code written above:
|
|
|
|
```
|
|
0
|
|
1
|
|
2
|
|
```
|
|
|
|
### The loop
|
|
|
|
Rust has an infinite loop. Yes, one with no condition for starting and no condition to stop. It just continues looping over and over again till infinity. But of course, has triggers to stop the loop execution from the code itself.
|
|
|
|
The syntax for this infinite loop is as follows:
|
|
|
|
```
|
|
loop {
|
|
<statement(s)>;
|
|
}
|
|
```
|
|
|
|
📋
|
|
|
|
These loops are mostly used in GUI software where exiting is an
|
|
|
|
_explicit_
|
|
|
|
operation.
|
|
|
|
Before I even give you an example, since this loop is quite special, let's first look at how to _exit_ it :p
|
|
|
|
To stop the execution of an infinite loop, the `break` keyword is used inside the loop.
|
|
|
|
Let's look at an example where only whole numbers between 0 and 3 (inclusive) are printed to the program output.
|
|
|
|
```
|
|
fn main() {
|
|
let mut var = 0;
|
|
|
|
loop {
|
|
if var > 3 {
|
|
break;
|
|
}
|
|
|
|
println!("{}", var);
|
|
var += 1;
|
|
}
|
|
}
|
|
```
|
|
|
|
The best way to interpret this particular example is to look at it as an unnecessarily expanded form of a `while` loop ;)
|
|
|
|
You have a mutable variable `var` with an initial value of 0 that is used as an iterator, kind of. The infinite loop starts with an `if` condition that _should_`var`_'s value be greater than 3, the_`break` _keyword should be executed_ . Later on, like the previous example of the `while` loop, `var`'s value is printed to the stdout and then its value is incremented by 1.
|
|
|
|
It produces the following output:
|
|
|
|
```
|
|
0
|
|
1
|
|
2
|
|
3
|
|
```
|
|
|
|
### Labelled loops
|
|
|
|
Let's say there are two infinite loops, one nested in the other. For some reason, the exit condition is checked in the innermost loop but this exit condition is for exiting out of the outermost loop.
|
|
|
|
In such a case, labelling the loop(s) might be beneficial.
|
|
|
|
💡
|
|
|
|
The use of labels
|
|
|
|
```
|
|
break
|
|
```
|
|
|
|
and
|
|
|
|
```
|
|
continue
|
|
```
|
|
|
|
keywords are not exclusive to the infinite loop. They can be used with all three loops that the Rust language offers.
|
|
|
|
Following is how to label a loop.
|
|
|
|
```
|
|
'label: loop {}
|
|
```
|
|
|
|
To tell the compiler that a loop is being labelled, start with a single quote character, type the label for it, and follow it with a colon. Then, continue with how you regularly define a loop.
|
|
|
|
When you need to break certain loop, simply specify the loop label like so:
|
|
|
|
```
|
|
break 'label;
|
|
```
|
|
|
|
Let's take a look at an example to better understand this.
|
|
|
|
```
|
|
fn main() {
|
|
let mut a = 0;
|
|
let mut b = 0;
|
|
|
|
'parent: loop {
|
|
a += 1;
|
|
|
|
loop {
|
|
println!("a: {}, b: {}", a, b);
|
|
b += 1;
|
|
|
|
if a + b == 10 {
|
|
println!("\n{} + {} = 10", a, b);
|
|
break 'parent;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
Here, I took two mutable variables `a` and `b` with the initial values set to 0 for both.
|
|
|
|
Later down, the outer-most loop is labelled `parent`. The 'parent' loop increments the value of varaible `a` by 1 and has an inner/child loop.
|
|
|
|
This child loop (on line 8) prints the values of variables `a` and `b`. Inside this loop, the value of `b` gets incremented by 1. And the exit condition is that `a + b == 10`. Meaning whenever the values stored in variables `a` and `b`, when added together, result in 10, the `parent` loop is broken. Even though the `break` condition on line 14 "belongs" to the inner loop, it breaks the `parent` loop.
|
|
|
|
Let's look at the program output now.
|
|
|
|
```
|
|
a: 1, b: 0
|
|
a: 1, b: 1
|
|
a: 1, b: 2
|
|
a: 1, b: 3
|
|
a: 1, b: 4
|
|
a: 1, b: 5
|
|
a: 1, b: 6
|
|
a: 1, b: 7
|
|
a: 1, b: 8
|
|
|
|
1 + 9 = 10
|
|
```
|
|
|
|
As evident from the program output, the loop stops as soon as `a` and `b` have the values 1 and 9 respectively.
|
|
|
|
### The continue keyword
|
|
|
|
If you have already used loops in any other programming language like C/C++/Java/Python, you might already know the use of the `continue` keyword.
|
|
|
|
While the `break` keyword is to stop the loop execution completely, the `continue` keyword is used to "skip" the **current iteration** of loop execution and start with the next iteration (if the conditions permit).
|
|
|
|
Let's look at an example to understand how the `continue` keyword works.
|
|
|
|
```
|
|
fn main() {
|
|
for i in 0..10 {
|
|
if i % 2 == 0 {
|
|
continue;
|
|
}
|
|
println!("{}", i)
|
|
}
|
|
}
|
|
```
|
|
|
|
In the code above, I have a `for` loop that iterates over whole numbers between 0 and 9 (inclusive). As soon as the loop starts, I put a conditional check to see if the number is even or not. If the number is even, the `continue` keyword is executed.
|
|
|
|
But if the number is odd, the number gets printed to the program output.
|
|
|
|
Let's first look at the output of this program.
|
|
|
|
```
|
|
1
|
|
3
|
|
5
|
|
7
|
|
9
|
|
```
|
|
|
|
As you can see, the loop appears to have been "going on" even though there clearly are even numbers between 0 and 9. But because I used the `continue` keyword, the loop execution stopped when that keyword was encountered.
|
|
|
|
The loop skipped whatever was under it and continued with the next iteration. That's why even numbers are not printed, but all odd numbers between 0 and 9 are printed to the proogram output.
|
|
|
|
### Conclusion
|
|
|
|
To conclude this long article, I demonstrated the use of 3 different loops: `for`, `while` and `loop`. I also discussed two keywords that affect the control flow of these loops: `break` and `continue`.
|
|
|
|
I hope that you now understand the appropriate use case for each loop. Please let me know if you have any questions.
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
via: https://itsfoss.com/rust-loops/
|
|
|
|
作者:[Pratham Patel][a]
|
|
选题:[lkxed][b]
|
|
译者:[译者ID](https://github.com/译者ID)
|
|
校对:[校对者ID](https://github.com/校对者ID)
|
|
|
|
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
|
|
|
[a]: https://itsfoss.com/author/pratham/
|
|
[b]: https://github.com/lkxed/
|
|
[1]: https://itsfoss.com/rust-conditional-statements |