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

文章目录

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

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

If 表达式

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

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

基本结构

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

特点和规则

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

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

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

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

示例

rust 复制代码
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 表达式,专门用于处理单一的模式匹配情况

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

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

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

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

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

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

    rust 复制代码
    let number = if condition { 5 } else { 6 };

loop 循环

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

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

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

rust 复制代码
fn main() {
    let mut count = 0;

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

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

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

rust 复制代码
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 循环

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

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

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

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

rust 复制代码
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 循环

基本结构
rust 复制代码
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 循环示例,该示例将会遍历一个向量并打印出每个元素。

rust 复制代码
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 循环来遍历一个字符串,并统计其中每个字符出现的次数。

rust 复制代码
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 并打印每个字符及其对应的计数。

match 表达式

Rust语言中的match表达式是模式匹配的一种方式,用于在多个分支中选择一个执行。它类似于其他编程语言中的switch语句,但是功能更加强大和灵活,可以匹配复杂的模式而不仅仅是整数或字符串值。

match表达式的语法结构

基本的match表达式的语法如下:

rust 复制代码
match value {
    pattern if guard_condition => expression,
    // 更多的 pattern...
    _ => default_expression, // 可选的默认分支
}
  • value 是你要匹配的值。
  • pattern 是你想要匹配的模式。
  • if guard_condition 是一个可选的条件,只有当这个条件为真时,模式才匹配。
  • expression 是如果模式匹配成功后要执行的代码块。
  • _ 是一个通配符模式,表示如果没有其他模式匹配成功,则执行default_expression

注意:所有可能的情况都必须被覆盖,要么显式地处理,要么通过使用通配符_来提供一个默认分支。如果不能覆盖所有情况,编译器将会报错。

示例代码
rust 复制代码
// 定义一个枚举类型UsState,这里只列举了两个州作为示例
enum UsState {
    Alabama,
    Alaska,
}

// 定义一个函数say_hello,接收一个UsState类型的参数state
fn say_hello(state: UsState) {
    // 使用match表达式来匹配传入的state值
    match state {
        // 如果state是Alabama,则打印"Let's go to the beach!"
        UsState::Alabama => println!("Let's go to the beach!"),
        // 如果state是Alaska,则打印"Maybe visit the glaciers?"
        UsState::Alaska => println!("Maybe visit the glaciers?"),
        // 如果没有其他模式匹配成功(即state不是Alabama也不是Alaska),则打印"Some other state."
        _ => println!("Some other state."),
    }
}

// 主函数,程序的入口点
fn main() {
    // 创建一个UsState枚举实例
    let current_state = UsState::Alabama;
    // 调用say_hello函数并传入当前的州
    say_hello(current_state);
}
rust 复制代码
// 定义一个名为calculate_length的函数,接收一个包含两个i32值的元组作为参数
fn calculate_length(x: (i32, i32)) -> String {
    // 使用match表达式来匹配元组x中的元素
    match x {
        // 如果元组的第一个元素和第二个元素都是0,则返回"Origin"
        (0, 0) => String::from("Origin"), // 这里使用String::from方法创建一个新的字符串
        // 如果元组的第一个元素是0但第二个元素不是0,则格式化并返回一个字符串
        (0, y) => format!("On the Y axis at {}", y), // format!宏用于创建格式化的字符串
        // 如果元组的第二个元素是0但第一个元素不是0,则格式化并返回一个字符串
        (x, 0) => format!("On the X axis at {}", x), // format!宏用于创建格式化的字符串
        // 如果元组的两个元素都不是0,则格式化并返回一个包含两个坐标值的字符串
        (x, y) => format!("({}, {})", x, y), // format!宏用于创建格式化的字符串
    }
}

// 主函数,程序的入口点
fn main() {
    // 创建一个包含两个i32值的元组
    let coordinates = (3, 4);
    // 调用calculate_length函数并传入坐标值
    let length = calculate_length(coordinates);
    // 打印返回的字符串
    println!("{}", length); // 输出"(3, 4)"
}
相关推荐
XH华8 分钟前
初识C语言之二维数组(下)
c语言·算法
南宫生30 分钟前
力扣-图论-17【算法学习day.67】
java·学习·算法·leetcode·图论
不想当程序猿_42 分钟前
【蓝桥杯每日一题】求和——前缀和
算法·前缀和·蓝桥杯
高山我梦口香糖1 小时前
[react]searchParams转普通对象
开发语言·前端·javascript
落魄君子1 小时前
GA-BP分类-遗传算法(Genetic Algorithm)和反向传播算法(Backpropagation)
算法·分类·数据挖掘
菜鸡中的奋斗鸡→挣扎鸡1 小时前
滑动窗口 + 算法复习
数据结构·算法
信号处理学渣1 小时前
matlab画图,选择性显示legend标签
开发语言·matlab
红龙创客1 小时前
某狐畅游24校招-C++开发岗笔试(单选题)
开发语言·c++
Lenyiin1 小时前
第146场双周赛:统计符合条件长度为3的子数组数目、统计异或值为给定值的路径数目、判断网格图能否被切割成块、唯一中间众数子序列 Ⅰ
c++·算法·leetcode·周赛·lenyiin
jasmine s1 小时前
Pandas
开发语言·python