rust语言流程控制

2023-02-10 09:37:29 浏览数 (1)

流程控制

rust代码是从上至下顺序执行的,在这个过程中,可以通过循环,分支等流程控制方式来实现相应的逻辑。

if-else

rust的if-else和其它语言中的类似,但是if-else在rust中是一个表达式,并且所有分支必须返回相同的类型。下面通过例子来具体看看。

代码语言:javascript复制
fn main() {
    let a = 1;
    let b = 2;

    if a > b {
        println!("{}", "a>b");
    }else {
        println!("{}", "a<=b");
    }

    let c = if a > b {
        println!("{}", "a>b");
        a
    }else {
        println!("{}", "a<=b");
        b
    };          // 当if-else表达式的值被let语句使用的时候,需要在最后加上分号,并且保证a,b返回的值是同类型。

    println!("{}", c);  // c的值是由if表达式执行到的分支所确定的,因此c的值是2
}

rust的条件表达式不需要使用括号包括起来。除此之外rust的if表达式还有一个if let,由于if let本质上是和match一样的模式匹配,不在此处描述。

使用else if处理多重条件

和其它语言类似,rust的if-else语句可以有大量的分支用来处理多重条件。例如:

代码语言:javascript复制
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”。有一点要注意,就算有多个分支能匹配,也只有第一个匹配的分支会被执行!(例如这段代码中的number is divisible by 2虽然匹配成功,但是不会被执行。)

for循环

rust的for循环和python,javascript的for循环看起来很像,语义如下:

代码语言:javascript复制
for 元素 in 集合 {
  // 使用元素
}

注意,使用 for 时我们往往使用集合的引用形式,这能避免集合的所有权转移。(除非你之后不再使用该集合),如果是实现了Copy trait的数组,那么不会导致所有权的转移。如果想在循环中,修改该元素,可以使用mut关键字。例如:

代码语言:javascript复制
for num in &mut nums  {     // 可变引用,修改元素的值
    *num  = 3;              // 注意这里需要手动解引用,
}
println!("{:?}", nums);

获取元素索引

在循环中获取元素的索引,可以使用下面的方式。

代码语言:javascript复制
for (i, v) in nums.iter().enumerate() {
    println!("第{}个元素是{}", i, v);
}

下表是可变引用,不可变引用,转移所有权的等价使用方式。

使用方法

等价使用方式

所有权

for item in collection

for item in IntoIterator::into_iter(collection)

转移所有权

for item in &collection

for item in collection.iter()

不可变借用

for item in &mut collection

for item in collection.iter_mut()

可变借用

for循环能够对迭代器进行循环迭代。(正如上面表格中的等价形式一样,for是对迭代器进行的。)

控制循环执行次数

下面是一个使用for循环控制循环体执行10次的例子。

代码语言:javascript复制
for i in 0..10 {
    println!("{}", i);
}

如果你不需要使用i,那么可以使用_来代替。在 Rust 中 _ 的含义是忽略该值或者类型的意思,如果不使用 _,那么编译器会给你一个 变量未使用的 的警告。例如:

代码语言:javascript复制
for _ in 0..=10 {
    println!("Hello rust!");
}

continue

和其它编程语言一样,continue都是跳过本次循环,开始下次循环。例如:

代码语言:javascript复制
for i in 0..=10{
    if i % 2 == 0 {
        continue;
    }
    println!("{}", i);
}

程序执行结果如下所示:

代码语言:javascript复制
1
3
5
7
9

break

和其它编程语言一样,break可以跳出整个循环,使当前循环结束。例如:

代码语言:javascript复制
for i in 1..9 {
    if i == 5 {
        break;
    }
    println!("{}", i);
}

程序执行结果如下所示:

代码语言:javascript复制
1
2
3
4

while循环

while循环相比for循环,可能没有那么常用。当循环条件为 true 时,继续循环,条件为 false,跳出循环。例如:

代码语言:javascript复制
let mut count = 0;
while count < 3 {
    println!("{}", count);
    count  = 1;
}

loop循环

rust提供了loop循环,它是一个简单的无限循环。因此在使用loop循环的时候要格外小心,如果你忘记配合break来使用,那程序可能就在循环里永远出不来了。另外一点是loop循环是一个表达式,而for和while循环不是。例如:

代码语言:javascript复制
let result = loop {
    count  = 1;
    if count == 10 {
        break count * 2;
    }
};
println!("{}", result);

这段代码中,通过break带回了返回值。打印出20

循环标签

和大多数语言一样,再存在多层循环嵌套的情况下,break 和 continue 应用于此时最内层的循环。rust提供了标签结合continue,break来使用,使这些标签应用于已标记的循环而不是内层的循环。例如:

代码语言:javascript复制
fn main() {
    let mut count = 0;
    'outer: loop {
        'inner1: loop {
            if count >= 20 {
                // 这只会跳出 inner1 循环
                break 'inner1; // 这里使用 `break` 也是一样的
            }
            count  = 2;
        }

        count  = 5;

        'inner2: loop {
            if count >= 30 {
                break 'outer;
            }

            continue 'outer;
        }
    }

    assert!(count == 30)
}

这段代码需要仔细看,不能大意。因为有的break和continue是跳到某一个标签,而不是最内层的循环。循环标签使得循环更加强大,但是带来的后果是使得代码的逻辑变得更加复杂难懂。非必要不使用循环标签。

参考资料

  1. rust程序设计语言
  2. rust语言圣经

0 人点赞