【🔥前端学rust】流程控制

78 阅读8分钟

前言

这是 【🔥前端学rust】 系列文章的第五篇文章了。其他内容如下:

  1. 【🔥前端学rust】花式println和注释
  2. 【🔥前端学rust】基础数据类型
  3. 【🔥前端学rust】复合数据类型
  4. 【🔥前端学rust】函数

这篇文章我们学习 rust 中的流程控制。rust 是一种注重安全性和并发性的系统编程语言,提供了多种流程控制语句,包括条件语句 (ifelsematch)、循环语句 (loopwhilefor)、模式匹配语句 (if let 和 while let) 以及其他控制流语句 (continuebreak, return)。

条件语句

if/else

rust 中的 if 语句和大多数语言类似,用于基于条件执行代码。if 语句用于执行满足条件的代码块。else 部分则是当条件不满足时执行的代码块。不同的是,rust 语言中的布尔判断条件不必使用小括号包裹,且每个条件后面都跟着一个代码块。if-else 条件选择是一个表达式,并且所有分支都必须返回相同的类型。

n main() {
  let number = 5;

  if number < 10 {
    println!("The number is less than 10");
  } else if number == 10 {
    println!("The number is exactly 10");
  } else {
    println!("The number is greater than 10");
  }
}

image.png

需要注意的是 rustif 是一种表达式,可以返回值。可以实现三元表达式的效果。

fn main() {
  let number = 5;
  let message = if number < 10 {
    "The number is less than 10"
  } else {
    "The number is greater than or equal to 10"
  };
// ^ 不要忘记在这里加上一个分号!所有的 `let` 绑定都需要它。
  println!("{}", message);
}

image.png

match

match 语句用于多分支的选择,类似于 JavaScript 中的 switch-case 结构。但其更加强大和灵活。它可以匹配任何类型,并且可以使用模式匹配。

fn main() {
  let x = 5;

  match x {
    1 => println!("One"),
    2 | 3 => println!("Two or Three"),
    _ => println!("Other"), // `_` 是默认情况
  }
}

image.png

同样的 match 也可以作为表达式返回值。

fn main() {
  let boolean = true;
  let binary = match boolean {
    false => 0,
    true => 1,
  };

  println!("{} -> {}", boolean, binary);
}

image.png

解构

match 可以解构枚举、元组、指针、结构体等数据类型。

  1. 解构枚举
#[allow(dead_code)]
enum Direction {
  North,
  South,
  East,
  West,
}

fn main() {
  let direction = Direction::North;

  match direction {
    Direction::North => println!("Going North"),
    Direction::South => println!("Going South"),
    Direction::East => println!("Going East"),
    Direction::West => println!("Going West"),
  }
}

image.png

  1. 解构元组
fn main() {
  let triple = (0, -2, 3);

  println!("Tell me about {:?}", triple);
  
  match triple {
    // 解构出第二个和第三个元素
    (0, y, z) => println!("First is `0`, `y` is {:?}, and `z` is {:?}", y, z),
    (1, ..)  => println!("First is `1` and the rest doesn't matter"),
    // `..` 可用来忽略元组的其余部分
    _      => println!("It doesn't matter what they are"),
    // `_` 表示不将值绑定到变量
  }
}

image.png

  1. 解构结构体
struct Person {
  name: String,
  age: u32,
}

fn main() {
  let person = Person { name: "Alice".to_string(), age: 30 };

  match person {
    Person { name: ref n, age: a } => {
      println!("Name: {}, Age: {}", n, a);
    },
  }
}

image.png

  1. 解构指针和引用 对指针来说,解构(destructure)和解引用(dereference)要区分开。
  • 解引用使用 *
  • 解构使用 &ref、和 ref mut
fn main() {
  let mut value: i32 = 40;
  let value_ref: &mut i32 = &mut value;

  match value_ref {
    n => {
      *n += 1; // 修改值
      println!("Updated value: {}", n);
    },
  }
}

image.png

卫语句

rust 中,match 语句允许使用匹配守卫(guard clauses),这是一种附加条件,可以在匹配分支中加入额外的逻辑检查。这使得 match 更加灵活,可以处理更复杂的条件。匹配守卫是在 => 之前使用 if 来指定的一个布尔表达式。只有当该布尔表达式的值为 true 时,才会执行对应的分支。

#[allow(dead_code)]
#[derive(Debug)]
enum Color {
  Red(u8, u8, u8), // RGB values
  Green(u8, u8, u8),
  Blue(u8, u8, u8),
}

fn main() {
  let color = Color::Red(255, 0, 0);

  match color {
    Color::Red(r, g, b) if r == 255 && g == 0 && b == 0 => {
      println!("This is pure red.");
    },
    Color::Green(r, g, _) if r < 100 && g > 150 => {
      println!("This green has high green component.");
    },
    Color::Blue(_, _, _) => {
      println!("This is some shade of blue.");
    },
    _ => {
      println!("Unknown color.");
    },
  }
}

image.png

绑定

rust 中,match 表达式可以使用 @ 符号来绑定一个匹配到的值到一个变量。这种方式允许你在匹配的同时获取这个值,以便在匹配体中使用。

fn main() {
  let value = 42;

  match value {
    n @ 1..=10 => println!("The value is between 1 and 10: {}", n),
    n @ 11..=20 => println!("The value is between 11 and 20: {}", n),
    n @ 21..=30 => println!("The value is between 21 and 30: {}", n),
    n @ 31..=40 => println!("The value is between 31 and 40: {}", n),
    n @ 41..=50 => println!("The value is between 41 and 50: {}", n),
    _ => println!("The value is out of range"),
  }
}

image.png

可以使用绑定来“解构” enum 变体,例如 Option

fn some_number() -> Option<u32> {
  Some(42)
}

fn main() {
  match some_number() {
    // 得到 `Some` 可变类型,如果它的值(绑定到 `n` 上)等于 42,则匹配。
    Some(n @ 42) => println!("The Answer: {}!", n),
    // 匹配任意其他数字。
    Some(n) => println!("Not interesting... {}", n),
    // 匹配任意其他值(`None` 可变类型)。
    _ => (),
  }
}

image.png

循环语句

while

while 循环会在给定的条件为真时反复执行一段代码。

fn main() {
  let mut number = 3;

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

  println!("Liftoff!");
}

image.png

for

for 循环遍历集合或其他可迭代对象中的每一个元素,如数组、范围、集合等。

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

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

  // 使用 range 创建一个从 1 到 9 的序列
  for i in 1..10 {
    println!("num is: {}", i);
  }
}

image.png

loop

loop 循环是一个无限循环,除非显式地退出它。通常使用 break 或 return 语句来退出循环。

fn main() {
  let mut count = 0;

  loop {
    count += 1;
    if count == 5 {
      break; // 当计数达到 5 时退出循环
    }
    println!("Counting up: {}", count);
  }

  println!("Loop finished!");
}

image.png

嵌套循环和标签

rust 中,你可以使用 'label 标签(labels)来创建嵌套循环或控制嵌套循环的行为。标签是一个标识符,后面跟着一个冒号,可以用于标识一个循环。然后,你可以使用 breakcontinue 语句配合标签来跳出指定的循环。

fn main() {
  'outer: loop {
    println!("Starting outer loop iteration.");

    'inner: loop {
      println!("Starting inner loop iteration.");

      let should_break_outer = true;
      if should_break_outer {
        break 'outer; // 跳出外层循环
      }

      let should_continue_inner = false;
      if should_continue_inner {
        continue 'inner; // 继续内层循环的下一次迭代
      }

      println!("Inner loop completed this iteration.");
    }
  }

  println!("Both loops have been exited.");
}

image.png

loop 循环返回值

rust 中,loop 循环本身没有直接返回值的功能,但它可以通过 break 语句配合表达式来从 loop 中返回一个值。具体来说,break 语句后面跟上一个表达式,这个表达式的结果将会作为 loop 循环的返回值。

fn main() {
  let result = loop {
    let x = 5;
    let y = 10;

    // 条件满足时,返回一个值
    if x + y > 10 {
      break x + y; // 使用 break 返回值
    }
  };

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

image.png

if letwhile let

rust 中,if let 和 while let 是两个非常有用的模式匹配工具,用来处理枚举类型中的某些变体,主要用于简化对 Option 和 Result 枚举类型的处理。这两个结构允许你更简洁地编写代码,同时保持良好的可读性和安全性。

if let

if let 用于在条件语句中进行模式匹配。它允许你匹配某个表达式的特定模式,并在匹配成功时执行相应的代码。

fn main() {
  let some_value = Some(42);

  if let Some(x) = some_value {
    println!("Got a value: {}", x);
  } else {
    println!("No value!");
  }
}

image.png

while let

while let 主要用于循环场景,类似于 while 循环,但同样适用于模式匹配。它可以在匹配成功时持续执行循环体内的代码,直到不再匹配为止。

fn main() {
  let numbers = vec![Some(1), Some(2), Some(3), None, Some(4)];
  let mut iterator = numbers.into_iter();

  while let Some(Some(x)) = iterator.next() {
    println!("Got a number: {}", x);
  }
}

image.png

跳出控制

rust 中,breakcontinue 和 return 是三种常用的流程控制关键字,它们各自有不同的用途和效果。

break

break 语句用于立即退出一个循环(如 loopforwhile),并可选择性地返回一个值。

fn main() {
  for i in 0..10 {
    if i == 5 {
      break; // 当 i 等于 5 时,跳出循环
    }
    println!("{}", i);
  }
  println!("Loop ended");
}

image.png

continue

continue 语句用于跳过当前循环的剩余代码,并直接开始下一次循环迭代。

fn main() {
  for i in 0..10 {
    if i % 2 == 0 {
      continue; // 如果 i 是偶数,则跳过本次循环
    }
    println!("{}", i); // 只会打印奇数
  }
}

image.png

return

return 关键字用于从函数中返回一个值并立即退出该函数。如果没有指定返回值,则默认返回 ()(即单元类型)。

fn add(a: i32, b: i32) -> i32 {
  return a + b; // 返回 a 和 b 的和
}

fn main() {
  let sum = add(5, 7);
  println!("The sum is {}", sum);
}

image.png

总结

  • 条件语句if 和 match 用于根据不同的条件执行不同的代码块。
  • 循环语句loopwhile, 和 for 分别用于无限循环、条件循环和遍历循环。
  • 模式匹配语句if let 和 while let 用于简洁地处理 Option 和 Result 类型。
  • 跳出语句: breakcontinue 和 return 作为流程控制关键字,可以提前跳出流程。

rust 提供了灵活且强大的流程控制方式,包括条件语句、循环语句、模式匹配等。这些控制结构使得 rust 适用于多种编程场景,并能够编写高效和安全的代码。