Rust 的控制流

35 阅读5分钟

Control flow

一. if 表达式

表达式三个字就表明这玩意儿是可以有返回值的,有 C、C++、Java 经验的老手们会想起if 语句。没错,在编程世界里,语句(Statement)表示没有返回值,而表达式(Expression)则意味着有返回值

// #![allow(unused_parens)] // 允许编译器存在无用括号,不推荐
fn main(){
  let is_running = true;
  // 注意 if 后面的小括号
  if(is_running){
    println!("Running");
  }else{
    println!("Not Running");
  }

}

上述的代码片段,对于大多数 Java、C/C++的编程者而言,都是再熟悉不过啦(司空见惯)。

运行结果

根据 Rust 编译器的精确提示,if 条件表达式的小括号是不必要的(跟 Python 有点类似)。建议我们 remove。(PS:我们也可以通过属性来修改编译器的行为,但是不推荐)

既然我们刚才强调 Rust 的if 表达式,那上述代码就可以改写为如下形式:

fn main(){
  let is_running = false;
  // 这就是表达式的魅力所在
  let state = if is_running {"Running"} else {"Not Running"};

  println!("{}",state);
}

下面我们再看一个多重表达,跟其它语言类似,这里一笔带过。

fn main(){
    let score = 90;

    if score == 100 {
        println!("Grade = {}","天才");
    }else if score >= 85 && score < 100 {
        println!("Grade = {}","优秀");
    }else if score >= 75 && score < 85{
        println!("Grade = {}","良好");
    }else if score >= 60 && score < 75{
        println!("Grade = {}","及格");
    }else{
        println!("Grade = {}","不及格");
    }
}

二. 循环控制

在职业生涯中,不少人在编码中可能会无意识的犯一个错误:死循环

。这里假设大家每天睡觉时间,都会有好事发生,就如下代码的输出一样。

fn main(){

   while true {
      println!("支付宝到账100W");
   }

}

运行结果

Rust 编译器觉得我们做梦的方式不够优雅,还特地给我们推荐了loop 关键字

2.1 loop(死)循环

其实就是给我们提供了一种死循环的标准写法。~ 2333

fn main() {
  let mut i = 0;
  loop {
      i += 1;
      if i % 2 != 0 {
        println!("{i}:支付宝到账1 Billon");
       }else {
        println!("今天我撒钱啦!");
        continue;
       }

       if i > 100 {
         println!("我有{i} Billon,够花了!!!");
         break;
       }
   }
}

退出循环的两个关键字continuebreak,跟其它语言没有任何区别。

  1. break:退出整个循环;
  2. continue: 跳出本次循环,继续执行下一次循环;

2.2 while 循环

while循环和其它语言没有太大区别。不要问问就是没有(Rust 确实没有 do while 循环。

耳畔是否响起了“当山峰没有棱角的时候 当河水不再流,当时间停住日夜不分 当天地万物化为虚有...”

fn main(){
    let mut bank_deposit = 0;

    while bank_deposit < 10000{
        bank_deposit += 100;
        println!("银行存款:{}W",bank_deposit);
    }

    println!("退休养老吧,醒醒别做梦了!!!");
}

2.3 for 循环

无论你使用哪种编程语言(C/C++、Java and so on),for 循环应该是大家最常用的。但是形式略有差异。

2.3.1 主流编程语言的 for 循环

在主流的编程语言中(C/C++、Java)我们见到的都是这种形式。

for 循环里包含三个部分

  1. 初始化变量
  2. 条件;
  3. 变量自增、自减等操作

for (initialization; condition; increment) {
  // 循环体
 }

这里已打印数字为例(以 C++为例),


#include <iostream>

int main() {
    for (int i = 0; i < 10; i++) {
        std::cout << i << std::endl;
    }
    return 0;
}

在 C++11 中引入了基于范围的 for 循环用于遍历数组或容器

#include <iostream>
#include <vector>

int main() {
    std::vector<int> vec = {1, 2, 3, 4, 5};

    for (int value : vec) {
        std::cout << value << std::endl;
    }

    return 0;
}
2.3.1 Rust 的 for 循环 和 Range

但是在 Rust 中的 for 循环是这样的(for ... in ...),有点类似于 C++11 的增强 for 循环。

fn main() {
    let arr = [1, 2, 3, 4, 5];
    for num in arr {
        println!("{}", num);
    }
}

沉默中

如何用 Rust 的 for 循环快捷的打印 1~100 呢?(总不能让我写进数组里再吐出来吧),这里就引出了 Rust 标准库的 Range

range start..end contains all values with start <= x < end.

It is empty if start >= end.

start...end 等价于 数学意义上的“左闭右开”区间。

fn main(){
  // 因为Range是左闭右开,所以打印1~100,end为101
  for i in 1..101 {
        println!("{i}");
    }
}

值得注意的是,Rust在start >= end的情况下编译器居然不报Error或者Warn,有点莫名其妙。[PS:猜测后续可能要倒序输出吧]

fn main(){
  // 第一感觉是不是要倒序输出呢?
  for i in 5..1 {
     println!("{i}");
  }
}

这段代码不会有任何输出,因为官方文档写的很清楚:It is empty if start >= end.

这里需要明白,Rust的for循环格式:

// 1.  variable 变量,此处简化了let mut 的变量声明,非常便利
// 2. Iterator 迭代器,

for variable in Iterator{
  // do your work
}

通过以上内容,应该能体会到Iterator的重要性。


三. 模式匹配

3.1 match表达式

有C/C++、Java编程语言的同学,脑袋里或许有个疑问?Rust中有switch吗?

答案是没有,但是别急,咱有match表达式

Python 3.0的同学你别得意,Rust是match表达式,不是语句哦。

match关键字 : Control flow based on pattern matching.(控制流基于模式匹配)

fn main() {
    let position = 1;

    let rank = match position {
        1 => "冠军(Champion)",
        2 => "亚军(Runner-up)",
        3 => "季军(Third place)",
        _ => "其它(Other)",
    };

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

由于篇幅原因,这里就不展开讲match关键字枚举 Option的关系,后面有需要单独开篇。

if let

if let 是 Rust 中处理模式匹配的一种简洁方式,适用于只需要匹配一个模式的情况

// 这里就是我们只关心“冠军”的 if let写法。
fn main() {
    let position = 2;

    let rank = if let 1 = position {
        "冠军(Champion)"
    } else {
        "其它(Other)"
    };
    println!("The number is: {}", rank);
}

在实际Rust开发过程中,通过使用 matchOption,可以有效地处理可能不存在(None)的值,并根据不同的情况执行相应的代码。if let 语法则进一步简化了只需处理一个变体的情况,使代码更加简洁和易读。

理解并掌握这些模式和用法将会帮助我们更好地编写更加健壮和安全的 Rust 代码。