基础篇-控制流

  • 木头
  • 更新于 2023-02-16 13:52
  • 阅读 1800

if,循环

根据条件是否为真来决定是否执行某些代码,以及根据条件是否为真来重复运行一段代码的能力是大部分编程语言的基本组成部分。Rust 代码中最常见的用来控制执行流的结构是 if 表达式和循环。

if 表达式

if表达式允许根据条件执行不同的代码分支。你提供一个条件并表示 “如果条件满足,运行这段代码;如果条件不满足,不运行这段代码。”

fn main() {
    let number = 3;

    if number < 5 {
        println!("condition was true");
    } else {
        println!("condition was false");
    }
}

所有的 if 表达式都以 if关键字开头,其后跟一个条件。在这个例子中,条件检查变量 number 的值是否小于5。在条件为 true 时希望执行的代码块位于紧跟条件之后的大括号中。if 表达式中与条件关联的代码块有时被叫做 arms

也可以包含一个可选的 else 表达式来提供一个在条件为false 时应当执行的代码块,这里我们就这么做了。如果不提供 else 表达式并且条件为 false 时,程序会直接忽略 if 代码块并继续执行下面的代码。

尝试运行代码,应该能看到如下输出:

$ cargo run       
   Compiling variables v0.1.0 (/projects/variables)
    Finished dev [unoptimized + debuginfo] target(s) in 0.61s
     Running `target/debug/variables`
condition was true

使用 else if 处理多重条件

可以将 else if 表达式与 ifelse组合来实现多重条件。例如:

fn main() {
    let number = 6;

    if number % 4 == 0 {
        println!("number is divisible by 4");
    } else if number % 3 == 0 {
        println!("number is divisible by 3");
    } else if number % 2 == 0 {
        println!("number is divisible by 2");
    } else {
        println!("number is not divisible by 4, 3, or 2");
    }
}

这个程序有四个可能的执行路径。运行后应该能看到如下输出:

$ cargo run  
   Compiling variables v0.1.0 (/projects/variables)
    Finished dev [unoptimized + debuginfo] target(s) in 0.32s
     Running `target/debug/variables`
number is divisible by 3

当执行这个程序时,它按顺序检查每个 if 表达式并执行第一个条件为 true 的代码块。注意即使 6 可以被 2 整除,也不会输出 number is divisible by 2,更不会输出 else块中的 number is not divisible by 4, 3, or 2。原因是 Rust 只会执行第一个条件为 true 的代码块,并且一旦它找到一个以后,甚至都不会检查剩下的条件了。

在 let 语句中使用 if

因为 if 是一个表达式,我们可以在 let 语句的右侧使用它,例如:

fn main() {
    let condition = true;
    let number = if condition { 5 } else { 6 };

    println!("The value of number is: {number}");
}

if 表达式的返回值赋给一个变量,number 变量将会绑定到表示 if 表达式结果的值上。运行这段代码看看会出现什么:

$ cargo run
   Compiling variables v0.1.0 (/projects/variables)
    Finished dev [unoptimized + debuginfo] target(s) in 0.32s
     Running `target/debug/variables`
The value of number is: 5

代码块的值是其最后一个表达式的值,而数字本身就是一个表达式。在这个例子中,整个 if 表达式的值取决于哪个代码块被执行。这意味着 if 的每个分支的可能的返回值都必须是相同类型;在上面示例中,if 分支和 else 分支的结果都是 i32 整型。如果它们的类型不匹配,如下面这个例子,则会出现一个错误:

fn main() {
    let condition = true;

    let number = if condition { 5 } else { "six" };

    println!("The value of number is: {number}");
}

当编译这段代码时,会得到一个错误。ifelse 分支的值类型是不相容的,同时 Rust 也准确地指出在程序中的何处发现的这个问题:

$ cargo run  
   Compiling variables v0.1.0 (/projects/variables)
error[E0308]: `if` and `else` have incompatible types
 --> src/main.rs:4:44
  |
4 |     let number = if condition { 5 } else { "six" };
  |                                 -          ^^^^^ expected integer, found `&str`
  |                                 |
  |                                 expected because of this

For more information about this error, try `rustc --explain E0308`.
error: could not compile `variables` due to previous error

if 代码块中的表达式返回一个整数,而 else 代码块中的表达式返回一个字符串。这不可行,因为变量必须只有一个类型。

循环

多次执行同一段代码是很常用的,一个循环执行循环体中的代码直到结尾并紧接着回到开头继续执行,Rust 为此提供了三种循环:loopwhilefor

loop

loop 关键字告诉 Rust 一遍又一遍地执行一段代码直到你明确要求停止,例子:

fn main() {
    loop {
        println!("again!");
    }
}

当运行这个程序时,我们会看到连续的反复打印 again!,直到我们手动停止程序。大部分终端都支持一个快捷键,ctrl-c,来终止一个陷入无限循环的程序。尝试一下:

 $ cargo run
   Compiling variables v0.1.0 (/projects/variables)
    Finished dev [unoptimized + debuginfo] target(s) in 0.33s
     Running `target/debug/variables`
again!
again!
again!
again!
again!
again!
again!
^Cagain!

Rust提供了一种从代码中跳出循环的方法。可以使用 break关键字来告诉程序何时停止循环。

从循环返回值

loop 的一个用例是重试可能会失败的操作,比如检查线程是否完成了任务。然而你可能会需要将操作的结果传递给其它的代码。如果将返回值加入你用来停止循环的 break 表达式,它会被停止的循环返回:

fn main() {
    let mut counter = 0;

    let result = loop {
        counter += 1;

        if counter == 10 {
            break counter * 2;
        }
    };

    println!("The result is {result}");
}

在循环之前,我们声明了一个名为counter 的变量并初始化为 0。接着声明了一个名为 result 来存放循环的返回值。在循环的每一次迭代中,我们将 counter 变量加 1,接着检查计数是否等于 10。当相等时,使用 break 关键字返回值 counter * 2。循环之后,我们通过分号结束赋值给 result 的语句。最后打印出 result 的值,也就是 20

运行这段代码看看结果是多少:

$ cargo run
   Compiling variables v0.1.0 (/projects/variables)
    Finished dev [unoptimized + debuginfo] target(s) in 0.30s
     Running `target/debug/variables`
The result is 20

在多个循环之间消除歧义

如果存在嵌套循环,break 和 continue 应用于此时最内层的循环。你可以选择在一个循环上指定一个 循环标签(loop label),然后将标签与 breakcontinue 一起使用,使这些关键字应用于已标记的循环而不是最内层的循环。下面是一个包含两个嵌套循环的示例:

fn main() {
    let mut count = 0;

    'counting_up: loop {
        println!("count = {count}");
        let mut remaining = 10;

        loop {
            println!("remaining = {remaining}");
            if remaining == 9 {
                break; //退出内层循环
            }
            if count == 2 {
                break 'counting_up; //退出外层循环
            }

            remaining -= 1;
        }

        count += 1;
    }
    println!("End count = {count}");
}

外层循环有一个标签 counting_up,它将从 0 数到 2。没有标签的内部循环从 10 向下数到 9。第一个没有指定标签的break将只退出内层循环。break 'counting_up; 语句将退出外层循环。这个代码打印:

$ cargo run
   Compiling variables v0.1.0 (/projects/variables)
    Finished dev [unoptimized + debuginfo] target(s) in 0.35s
     Running `target/debug/variables`
count = 0
remaining = 10
remaining = 9
count = 1
remaining = 10
remaining = 9
count = 2
remaining = 10
End count = 2

while

在程序中计算循环的条件也很常见。当条件为 true,执行循环。当条件不再为 true,调用 break停止循环。这个循环类型可以通过组合 loopifelsebreak来实现。

然而,这个模式太常用了,Rust 为此内置了一个语言结构,它被称为 while 循环。示例:

fn main() {
    let mut number = 3;

    while number != 0 {
        println!("{number}");
        number -= 1;
    }

    println!("LIFTOFF!!!");
}

while:程序循环三次,每次数字都减一。接着,在循环结束后,打印出另一个信息并退出

$ cargo run
   Compiling variables v0.1.0 (/projects/variables)
    Finished dev [unoptimized + debuginfo] target(s) in 0.26s
     Running `target/debug/variables`
3
2
1
LIFTOFF

这种结构消除了很多使用 loopifelsebreak 时所必须的嵌套,这样更加清晰。当条件为 true就执行,否则退出循环。

for

for循环是条件循环,即循环运行特定次数。 Rust语言中for循环的行为与其他语言略有不同。 执行for循环直到条件为假。可以使用 for 循环来对一个集合的每个元素执行一些代码:

fn main() {
    let a = [10, 20, 30, 40, 50];

    for element in a {
        println!("the value is: {element}");
    }
}

运行这段代码会打印出数组中的每一个元素:

$ cargo run
    Finished dev [unoptimized + debuginfo] target(s) in 0.00s
     Running `target/debug/variables`
the value is: 10
the value is: 20
the value is: 30
the value is: 40
the value is: 50

for 循环的安全性和简洁性使得它成为 Rust 中使用最多的循环结构。

  • 原创
  • 学分: 4
  • 分类: Rust
  • 标签:
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。
127 订阅 31 篇文章

1 条评论

请先 登录 后评论
木头
木头
0xC020...10cf
江湖只有他的大名,没有他的介绍。