Rust语言入门第七篇-控制流

Rust 的控制流是指程序执行过程中根据不同的条件选择不同的代码路径的能力。这是编程中一个核心的概念,帮助开发者实现逻辑判断、循环执行等基本结构。Rust 语言提供了一些关键的控制流构造,主要包括 if 表达式、match 表达式、loop、while、for 循环等。

If 表达式

if表达式在很多语言中很常见!if表达式允许条件不同执行不同的代码。

Rust 语言中的 if 表达式用于基于条件来执行不同的代码块。它的结构相对直接,但有几个特点需要注意,这些特点体现了 Rust 作为一门类型安全和表达式导向语言的特性。以下是 if 表达式的基本结构和一些关键点:

基本结构

if 条件 {
    // 当条件为 true 时执行的代码块
} else {
    // 当条件为 false 时执行的代码块(可选)
}

特点和规则

  1. 条件必须是布尔类型 (bool):与某些其他语言不同,Rust 不会隐式地将非布尔类型的值转换为布尔值。你需要确保 if 后面的条件表达式直接评估为一个布尔值。

  2. 代码块 ({}):即使 ifelse 分支只包含一条语句,你也必须使用花括号 {} 将其包裹起来。这是为了保持一致性,并且因为 Rust 中几乎所有东西都是表达式。

  3. 可选的 else if:为了实现多路分支,你可以链式使用 else if 语句。

if 条件1 {
    // 当条件1为 true 时执行
} else if 条件2 {
    // 当条件1为 false 并且条件2为 true 时执行
} else {
    // 当以上所有条件都为 false 时执行
}
  1. 表达式 vs. 语句:在 Rust 中,if 表达式实际上是一个表达式,这意味着它有返回值。每个分支的最后一项(即最后一个表达式的值)决定了整个 if 表达式的值。这使得 if 表达式可以在需要值的上下文中使用,比如赋值给变量或作为函数的返回值。

示例

fn calculate_result(score: i32) -> &'static str {
    if score > 90 {
        "Excellent"
    } else if score > 75 {
        "Good"
    } else {
        "Keep trying"
    }
}

fn main() {
    let score = 85;
    let result = calculate_result(score);
    println!("{}", result); // 输出 "Good"
}

在这个示例中,calculate_result 函数根据分数返回不同的评价等级,展示了 if 表达式如何用作返回值的计算。

let 语句中使用 if

在 Rust 中,结合 let 和 if 一起使用的结构被称为 if let 表达式。这是一种简化版的 match 表达式,专门用于处理单一的模式匹配情况

fn main() {
    let condition = true;
    let number = if condition { 5} else { 6 };
    println!("数字的值为:{number}");   
}

Rust语言入门第七篇-控制流-LMLPHP

这段 Rust 代码演示了如何使用 if 表达式作为值赋给变量,体现了 Rust 中 if 表达式不仅用于控制流,还可以直接产生值的特性。下面是详细的解释:

  1. 初始化变量 condition: 首先,定义了一个布尔型变量 condition 并将其值设为 true

    let condition = true;
    
  2. 使用 if 表达式赋值给 number: 接下来,定义了一个变量 number,其值由一个 if 表达式决定。这个 if 表达式检查 condition 的值:

    • 如果 conditiontrue,则执行 { 5 } 代码块,表达式的值为 5
    • 如果 conditionfalse,则执行 { 6 } 代码块,表达式的值为 6

    这里,if 表达式直接充当了一个值生成器,其结果(56)被赋给了 number

    let number = if condition { 5 } else { 6 };
    

loop 循环

loop 是 Rust 中的一种循环结构,它没有内置的终止条件,因此会一直执行循环体内的代码,直到遇到 break 语句为止。这对于需要无限循环或循环次数未知的情况非常有用。

基本结构
loop {
    // 循环体内的代码
    // 使用 break 语句来退出循环
}
特点
  1. 无终止条件loop 没有内置的终止条件,这意味着它会一直运行,直到你显式地使用 break 语句来停止它。
  2. 使用 break 退出:要终止 loop 循环,你必须在循环体内使用 break 语句。
  3. 使用 continue 跳过迭代:你也可以使用 continue 语句来跳过当前迭代,并立即开始下一次迭代。
示例

下面是一个简单的 loop 循环示例,该示例将会数到 10 并打印出每个数字。当计数达到 10 时,使用 break 语句退出循环。

fn main() {
    let mut count = 0;

    loop {
        println!("Count: {}", count);

        count += 1;
        if count == 10 {
            break;
        }
    }
}
综合示例

下面是一个稍微复杂的例子,该示例使用 loop 来模拟一个简单的游戏,玩家可以选择继续游戏或退出。

use std::io;

fn main() {
    let mut choice = 'y';

    loop {
        println!("Welcome to the game!");
        println!("Do you want to play? (y/n)");

        let mut input = String::new();
        io::stdin().read_line(&mut input)
            .expect("Failed to read line");
        choice = input.trim().chars().next().unwrap_or('n');

        if choice == 'y' {
            println!("Playing...");
        } else {
            println!("Exiting...");
            break;
        }
    }
}

在这个示例中:

  • 我们定义了一个变量 choice 来存储用户的输入。
  • 使用 loop 来重复询问用户是否想继续玩游戏。
  • 使用 std::io::stdin().read_line() 来读取用户的输入。
  • 使用 break 语句来结束循环,当用户输入 ‘n’ 时。

这个示例展示了如何使用 loop 来构建一个无限循环,并通过用户输入来控制循环的终止。

while 循环

基本结构
while condition {
    // 当条件为 true 时执行的代码块
}
特点
  • while 循环会在每次迭代前检查给定的条件。
  • 如果条件为 true,则执行循环体内的代码。
  • 如果条件为 false,则不执行循环体内的代码,并且循环终止。
  • loop 相比,while 循环提供了内置的终止条件,这使得它适合于那些你知道循环应该执行多少次或何时应停止的情况。
  • 在循环体内部,你可以使用 break 语句来提前终止循环。
  • 你也可以使用 continue 语句来跳过当前迭代并开始下一次迭代。
示例

下面是一个简单的 while 循环示例,该示例将会数到 10 并打印出每个数字。

fn main() {
    let mut count = 0;
    while count < 10 {
        println!("Count: {}", count);
        count += 1;
    }
}
综合示例

下面是一个稍微复杂的例子,该示例使用 while 循环来模拟一个简单的游戏,玩家可以选择继续游戏或退出。

use std::io;

fn main() {
    let mut choice = 'y';

    while choice == 'y' {
        println!("Welcome to the game!");
        println!("Do you want to play? (y/n)");

        let mut input = String::new();
        io::stdin().read_line(&mut input)
            .expect("Failed to read line");
        choice = input.trim().chars().next().unwrap_or('n');

        if choice == 'y' {
            println!("Playing...");
        } else {
            println!("Exiting...");
        }
    }
}

在这个示例中:

  • 我们定义了一个变量 choice 来存储用户的输入。
  • 使用 while 来重复询问用户是否想继续玩游戏,只要 choice'y'
  • 使用 std::io::stdin().read_line() 来读取用户的输入。
  • 用户可以通过输入 'n' 来退出游戏,此时 choice 变为 'n'while 循环的条件变为 false,循环终止。

loop 循环的区别

  • while 循环在每次迭代之前检查条件是否为 true,而 loop 没有内置的终止条件。
  • while 循环适合于那些你知道循环应该执行多少次或何时应停止的情况,而 loop 更适用于不知道循环次数的情况。
  • while 循环中,如果初始条件就是 false,那么循环体内的代码将不会被执行;而在 loop 循环中,你必须显式地使用 break 语句来终止循环。

for 循环

基本结构
for variable in iterable {
    // 循环体内的代码
}
详细说明
  • for 关键字:开始 for 循环。
  • variable:循环变量,用于保存每次迭代中的当前元素。这可以是任意有效的 Rust 标识符。
  • in 关键字:表示循环变量将在接下来的迭代中遍历的集合或范围。
  • iterable:可以被迭代的对象,它可以是实现了 IntoIterator 特性的任何类型,例如向量 (Vec<T>), 数组 ([T; N]), 字符串 (String&str), 范围 (a..ba..=b) 等。
  • { ... }:花括号包围的代码块,称为循环体。这里包含了每次迭代要执行的代码。
特点
  • 自动迭代for 循环会自动迭代 iterable 中的每个元素,并在每次迭代时将当前元素绑定到 variable
  • 类型推断:编译器会自动推断 variable 的类型,使其与 iterable 中的元素类型相匹配。
  • 范围迭代:可以使用范围来指定一个数值序列,例如 0..10 代表从 0 到 9 的整数序列。
  • 引用迭代:默认情况下,for 循环迭代的是 iterable 中元素的引用,这意味着原始数据结构不会被修改。如果你想获得元素的所有权,可以使用 .into_iter() 方法。
  • 可变迭代:如果你想在迭代过程中修改元素,可以使用 iter_mut() 方法来获取可变引用。
示例

下面是一个简单的 for 循环示例,该示例将会遍历一个向量并打印出每个元素。

fn main() {
    let numbers = vec![1, 2, 3, 4, 5];

    for number in &numbers {  // 迭代向量中的元素引用
        println!("Number: {}", number);
    }

    for number in numbers.into_iter() {  // 迭代向量中的元素所有权
        println!("Number: {}", number);
    }

    // 使用范围迭代
    for i in 0..10 {
        println!("i: {}", i);
    }
}
综合示例

下面是一个稍微复杂的例子,该示例使用 for 循环来遍历一个字符串,并统计其中每个字符出现的次数。

use std::collections::HashMap;

fn main() {
    let text = "hello world";
    let mut char_counts = HashMap::new();

    for c in text.chars() {  // 遍历字符串中的字符
        let count = char_counts.entry(c).or_insert(0);
        *count += 1;
    }

    for (char, count) in &char_counts {  // 遍历 HashMap 中的键值对
        println!("'{}': {}", char, count);
    }
}

在这个示例中:

  • 我们定义了一个字符串 text
  • 使用 for 循环来遍历字符串中的每个字符。
  • 使用 HashMap 来记录每个字符出现的次数。
  • 使用 entry 方法来获取或创建一个条目,然后增加计数。
  • 最后再次使用 for 循环来遍历 HashMap 并打印每个字符及其对应的计数。
08-01 04:47