Rust 基础系列 #7: 在 Rust 中使用循环
Rust
![](/data/attachment/album/202306/15/164034klkjbf3ibapjbbfk.jpg)


在 Rust 系列的 [上一篇文章](/article-15896-1.html) 中，我介绍了如何使用 `if` 和 `else` 关键字来处理 Rust 程序的控制流。


这是处理程序控制流的一种方法。另一种方法是使用循环。因此，让我们在本文中看看循环。


### Rust 中可用的循环


Rust 编程语言有三种不同的循环，基于你想要实现什么以及可用的内容：


* `for`
* `while`
* `loop`


我假设你对 `for` 和 `while` 已经很熟悉了，但 `loop` 对你来说可能是个新概念。让我们先从熟悉的概念开始。


### for 循环


`for` 循环主要用于迭代一种称为迭代器的东西。


这个迭代器可以从任何东西中创建，从数组、向量（很快就会介绍！）、一系列值，或者任何自定义的东西。这里的可能性是无限的。


来看看 `for` 循环的语法。



```
for 迭代变量 in 迭代器 {
    <语句>;
}

```

其中的 `迭代变量` 在大多数其他编程语言教程中通常被称为 `i` ; )


`迭代器` 可以是任何东西，只要它能告诉下一个值是什么，如果有的话。


来通过一个程序来理解这个。



```
fn main() {
    let my_arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];

    println!("迭代数组");
    for element in my_arr {
        println!("{}", element);
    }

    println!("\n迭代一个真正的迭代器");
    for element in my_arr.iter() {
        println!("{}", element);
    }

    println!("\nPython 风格的范围");
    for element in 0..10 {
        println!("{}", element);
    }
}

```

这里，我声明了一个数组，它包含从 0 到 9 的 10 个数字。在第 5 行的 `for` 循环中，我只是将这个数组指定为迭代器，Rust 会自动处理对这个数组的所有元素的迭代。不需要花哨的 `my_arr[i]` 魔法。


但是，在第 10 行，我调用了 `.iter()` 函数。这是一个明确的提及，它基于 `my_arr` 的值来获取一个迭代器。这个循环和第 5 行的循环之间唯一的区别是，这里你是通过在数组上调用 `.iter()` 函数来明确地调用它的。


*在这个上下文环境中*，在一个数据类型上调用 `.iter()` 函数不是必须的。因为这是一个数组，是语言本身提供的一种数据类型，Rust 已经知道如何处理它了。但是你 *需要* 在自定义数据类型中使用它。


最后，在第 15 行，我们有一个循环，它循环遍历一个范围。嗯，差不多是这样。如果你仔细看，这个范围看起来很像切片 “类型”。Rust 也知道这一点，并且 *为* 你处理了迭代（哈哈，明白了吗？）。



> 
> LCTT 译注：此处的梗是，“为你处理了迭代” 的英文原文是 “handles iteration *for* you"，其中的 “for” 与 “for 循环” 的 “for” 是同一个单词。
> 
> 
> 


输出如下：



```
迭代数组
0
1
2
3
4
5
6
7
8
9

迭代一个真正的迭代器
0
1
2
3
4
5
6
7
8
9

Python 风格的范围
0
1
2
3
4
5
6
7
8
9

```

### while 循环


`while` 循环可以被认为是非常类似于 `if` 条件语句。使用 `if` 语句，只要用户提供的条件为 `true`，`if` 语句体中的代码就会被执行 *一次*。


但是，在 `while` 循环中，如果条件评估为 `true`，循环就会开始循环循环体。只要条件继续评估为 `true`，循环就会继续迭代。


`while` 循环只有在循环完成当前迭代中所有语句的执行并且在检查条件时，它的结果为 `false` 时才会停止。


来看看 `while` 循环的语法...



```
while 条件 {
    <语句>;
}

```

看到了吗？和 `if` 条件语句非常相似！不过没有 `else` 块 ; )


来看一个程序来更好地理解这个。



```
fn main() {
    let mut var = 0;

    while var < 3 {
        println!("{var}");
        var += 1;
    }
}

```

我有一个可变变量 `var`，它的初始值为 0。只要可变变量 `var` 中存储的值小于 3，`while` 循环就会执行。


在循环中，`var` 的值被打印出来，然后它的值被增加 1。


这是上面代码的输出：



```
0
1
2

```

### loop 循环


Rust 有一个无限循环。是的，一个没有开始条件和停止条件的循环。它只是一直循环，直到永远。当然，它有触发器来停止代码本身的循环执行。


无限循环的语法如下：



```
loop {
    <语句>;
}

```


> 
> ? 这些循环主要用于 GUI 软件，退出是一个 *显式* 操作。
> 
> 
> 


在我给你一个例子之前，因为这个循环非常特殊，让我们先看看如何 *退出* 它 :p


要停止无限循环的执行，需要在循环内使用 `break` 关键字。


来看一个例子，只有 0 到 3 之间的整数（包括 0 和 3）才会被打印到程序输出。



```
fn main() {
    let mut var = 0;

    loop {
        if var > 3 {
            break;
        }

        println!("{}", var);
        var += 1;
    }
}

```

看待这个特定的例子的最好方法是将它看作是一个增加了一堆没有必要的东西的 `while` 循环 ; )


你有一个可变变量 `var`，它的初始值为 0，它被用作迭代器。无限循环从一个 `if` 条件开始，如果 `var` 的值大于 3，`break` 关键字就会被执行。后来，就像 `while` 循环的前一个例子一样，`var` 的值被打印到标准输出，然后它的值被增加 1。


它的输出如下：



```
0
1
2
3

```

### 标记循环


假设有两个无限循环，一个嵌套在另一个中。由于某种原因，退出条件在最内层循环中被检查，但这个退出条件是为了退出最外层循环。


在这种情况下，标记循环可能是有益的。



> 
> ? `break` 和 `continue` 关键字并不仅仅用于无限循环。它们可以用于 Rust 语言提供的所有三种循环。
> 
> 
> 


接下来是如何标记循环。



```
'标记: loop {}

```

要告诉编译器一个循环被标记了，从一个单引号字符开始，输入它的标签，然后跟着一个冒号。然后，继续使用你通常定义循环的方式。


当你需要退出某个循环时，只需像这样指定循环标签：



```
break '标记;

```

来看一个例子来更好地理解这个。



```
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;
            }
        }
    }
}

```

这里，我使用两个可变变量 `a` 和 `b`，它们的初始值都设置为 0。


然后，最外层的循环被标记为 `parent`。`parent` 循环将变量 `a` 的值增加 1，并有一个内部/子循环。


这个（在第 8 行的）子循环打印变量 `a` 和 `b` 的值。在这个循环内部，变量 `b` 的值增加了 1。退出条件是 `a + b == 10`。这意味着只要变量 `a` 和 `b` 中存储的值相加，结果为 10，`parent` 循环就会被打破。即使第 14 行的 `break` 条件“属于”内部循环，它也会打破 `parent` 循环。


来看看程序的输出。



```
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

```

就像从程序输出中可以看出的那样，循环在 `a` 和 `b` 分别具有值 1 和 9 时停止。


### continue 关键字


如果你已经在其他编程语言（如 C/C++/Java/Python）中使用过循环，你可能已经知道 `continue` 关键字的用法。


当 `break` 关键字用于完全停止循环执行时，`continue` 关键字用于“跳过”循环执行的 **当前迭代** 并从下一迭代开始（如果条件允许）。


来看一个例子来理解 `continue` 关键字的工作原理。



```
fn main() {
    for i in 0..10 {
        if i % 2 == 0 {
            continue;
        }
        println!("{}", i)
    }
}

```

在上面的代码中，我有一个 `for` 循环，它迭代了 0 到 9 之间的整数（包括 0 和 9）。一旦循环开始，我就设置了一个条件检查，看看这个数字是不是偶数。如果这个数字是偶数，`continue` 关键字就会被执行。


但是如果这个数字是奇数，这个数字就会被打印到程序输出。


来看看这个程序的输出。



```
1
3
5
7
9

```

正如你所看到的，循环似乎一直在“进行”，尽管 0 到 9 之间显然有偶数。但是因为我使用了 `continue` 关键字，当遇到这个关键字时，循环执行就会停止。


这个循环跳过了它下面的任何东西，并继续下一次迭代。这就是为什么偶数没有被打印出来，但是 0 到 9 之间的所有奇数都被打印到了程序输出中。


### 总结


要总结这篇长文，我演示了 3 种不同循环的用法：`for`、`while` 和 `loop`。我还讨论了两个关键字，它们影响这些循环的控制流：`break` 和 `continue`。


我希望你现在能理解每个循环的适当用例。如果你有任何问题，请告诉我。


*（题图：MJ/25579e09-ae1c-47d3-8266-3bd9a54456c0）*




---


via: <https://itsfoss.com/rust-loops/>


作者：[Pratham Patel](https://itsfoss.com/author/pratham/) 选题：[lkxed](https://github.com/lkxed/) 译者：[Cubik65536](https://github.com/Cubik65536) 校对：[wxy](https://github.com/wxy)


本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


OK
# Rust Basics Series #7: Using Loops in Rust

Loops are another way of handling control flow of your programs. Learn about for, while and 'loop' loops in Rust.

In the [previous article](https://itsfoss.com/rust-if-else/) 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)>;
}
```


*operation.*

*explicit*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.

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.