Rust - 流程控制

时间:2024-04-18 07:18:10

Rust 程序是从上而下顺序执行的,在此过程中,我们可以通过循环、分支等流程控制方式,更好的实现相应的功能。

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

(一)if表达式

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

当然,也可以包含一个可选的 else 表达式来提供一个在条件不满足时需要执行的代码块,如果不提供 else 表达式,那么在条件不满足时,程序则会直接忽略 if 代码块并继续向下执行。

fn main() {
    let number = 3;

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

值得注意的是,代码中的条件 必须 是 bool 值。如果条件不是 bool 值,程序就会错误。

例如以下代码,类似的写法可能在别的编程语言中可以顺利执行,但Rust却会报错:

fn main() {
    let number = 3;
    if number {
        println!("number was three");
    }
}

//编译结果:期待的是一个布尔值,但现在却是个数值。
//if number {
//   ^^^^^^ expected `bool`, found integer

可以很明显看出,Rust 并不会自动地将非布尔值转换为布尔值,必须总是显式地使用布尔值作为 if 的条件。
如果想要 if 代码块只在一个数字不等于 0 时执行,可以把 if 表达式修改成下面这样:

fn main() {
    let number = 3;

    if number != 0 {
        println!("number was something other than zero");
    }
}

如果想要 if 代码块只在一个数字只等于 0 时执行,可以把 if 表达式修改成下面这样:

fn main() {
    let number = 3;

    if number == 0 {
        println!("number was something other than zero");
    }
}

(二)使用else if处理多重条件

可以将 else if 与 if、else 组合在一起实现更复杂的条件分支判断:

fn main() {
    let n = 6;

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

程序执行时,会按照自上至下的顺序执行每一个分支判断,一旦成功,则跳出 if 语句块,最终本程序会匹配执行 else if n % 3 == 0 的分支,输出 “number is divisible by 3”。

有一点要注意,就算有多个分支能匹配,也只有从上至下第一个被匹配到的分支会被执行!

(三)在let语句中使用if

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

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

    println!("The value of number is: {}", number);
}
//运行结果:The value of number is: 5

在上面的例子中,number 变量将会绑定到表示 if 表达式结果的值上。

以上代码有以下几点要注意:

  1. if 语句块是表达式,这里我们使用 if 表达式的返回值来给 number 进行赋值:number 的值是 5。
    1. 记住:代码块的值是其最后一个表达式的值,而数字本身就是一个表达式。在这个例子中,整个 if 表达式的值取决于哪个代码块被执行。
  2. 用 if 来赋值时,要保证每个分支返回的类型一样,此处返回的 5 和 6 就是同一个类型,如果返回类型不一致就会报错。
    1. 例如:if 代码块中的表达式返回一个整数,而 else 代码块中的表达式返回一个字符串。这不可行,因为变量必须只有一个类型。Rust 需要在编译时就确切的知道 number 变量的类型,这样它就可以在编译时验证在每处使用的 number 变量的类型是有效的。

(四)loop循环

Rust中一共有三种循环,分别是loop、while、for。
loop关键字告诉Rust要反复的执行一块代码,直到我们自己明确要求停止才结束。

fn main() {
    loop {
        println!("again!");
    }
}
//无限打印again

想要让程序停止循环,我们通过在loop循环中使用break关键字来实现:

(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。当计数恰好为10时,使用 break 关键字返回 counter * 2 的值。(如果没有需要返回的值,直接就写成“ break; ”,结束loop循环。)

循环之后,我们通过分号结束赋值给 result 的语句(第10行)。最后打印出 result 的值,也就是 20。

(五)while条件循环

还有一种比较常见的循环模式是每次执行循环体之前都判断一次条件,再决定循环是否继续执行。

while条件循环就是为这种模式而生。

fn main() {
    let mut number = 3;

    //程序循环三次,每次数字都减一。
    while number != 0 {
        println!("{number}!");

        number -= 1;
    }
    
    //接着,在循环结束后,打印出另一个信息并退出。
    println!("LIFTOFF!!!");
}
/*
执行结果:
3
2
1
LIFTOFF!!!
*/

(六)for循环

for 循环是 Rust 中经常使用到的一种循环模式,不同于loop和while,它的功能不仅仅是“循环执行xx”这么简单,更重要的是它自身带来的“遍历”能力。

fn main() {
    for i in 1..=5 {
        println!("{}", i);
    }
}
/*
执行结果:
1
2
3
4
5
*/

以上代码循环输出了一个从 1 到 5 的序列,简单粗暴,核心就在于 for 和 in 的联动,语义表达如下:

for 元素 in 集合 {
  // 使用元素干一些你懂我不懂的事情
}

这个语法跟 JavaScript 还蛮像,应该挺好理解。

注意代码中的“1…=5”表示一个range范围,意为“1≥x≤5”。
而若修改为“1…5”,则意为“1≥x<5”。

使用for遍历集合:

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

    for element in a {
        println!("the value is: {element}");
    }
}
/*
执行结果:
the value is: 10
the value is: 20
the value is: 30
the value is: 40
the value is: 50
*/

当然,还有一个关于 **continue **关键字的知识点:
使用 continue 可以跳过当前当次的循环,开始下次的循环:

 for i in 1..4 {
     if i == 2 {
         continue;
     }
     println!("{}", i);
 }
//上面代码对 1 到 3 的序列进行迭代,且跳过值为 2 时的循环,输出如下:
//1
//3

同样的,continue 和 break 关键字一样,在任何一种循环中都能用。