跳过正文

7. 流程控制:flow control

·
Rust
rust-lang - 这篇文章属于一个选集。
§ 7: 本文

Rust 控制流结构包括:if 表达式、match 表达式和循环(loop、while、for)。

Rust 是表达式语言,if-else,if-let,while-let,match,loop,block 等都是表达式,可以用于变量赋值。

block 由分号结尾的语句(statement)组成,如果语句不以分号结尾,则它作为 block 的返回值,否则返回 unit type 值 ()。

let x = 5u32;

let y = {
    let x_squared = x * x;
    let x_cube = x_squared * x;

    x_cube + x_squared + x
};

// z 值是 ()
let z = {
    2 * x;
};

println!("x is {:?}", x);
println!("y is {:?}", y);
println!("z is {:?}", z);

let n = 5;
let big_n = if n < 10 && n > -10 {
    println!(", and is a small number, increase ten-fold");
    10 * n
} else {
    println!(", and is a big number, halve the number");
    n / 2
}; // 在 let 变量赋值时,} 右边的分号不能省!
println!("{} -> {}", n, big_n);

let mut counter = 0;
let result = loop {
    counter += 1;
    if counter == 10 {
        // loop break 返回值。
        break 10;
    }
};

循环支持嵌套,可以使用 break 'label 来跳出循环,label 的格式和 lifetime 一样,是 ’label 格式。’label 必须位于 loop/for/while 或 { 之前:

fn main() {
    'outer2: { // lable 位于 block { 之前
        let mut count = 0;
        'outer: loop {
            'inner1: loop {
                if count >= 20 {
                    break 'inner1;
                }
                count += 2;
            }

            count += 5;
            'inner2: loop {
                if count >= 30 {
                    break 'outer;
                }
                continue 'outer;
            }
        }
        break 'outer2;
    }
    println!("Success!");
}

break 可以返回值:

let answer = loop {
    if let Some(line) = next_line() {
        if line.starts_with("answer: ") {
            break line;
        }
    } else {
        break "answer: nothing";
    }
};

if-let 和 while-let 支持模式匹配语法: if/while let pattern = expression {} 。pattern 绑定的变量只在 expression 右边的 block 中有效:

// pattern 的元素数量必须与右边一致,解构后的变量 scope 是表达式右边的 block;
if let (a, 1) = (2, 4) {
    println!("a: {a}")
} else {
    // if let 不匹配的情况,else 子句是可选的。
    println!("not match!")
}

// if-let 和 if 可以混合使用
let x = Some(3);
let a = if let Some(1) = x {
    1
} else if x == Some(2) {
    2
} else if let Some(y) = x {
    y
} else {
    -1
};
assert_eq!(a, 3);

// 多个 pattern 可以使用 | 分割(pattern match 的标准语法)
enum E {
    X(u8),
    Y(u8),
    Z(u8),
}
let v = E::Y(12);
if let E::X(n) | E::Y(n) = v {
    assert_eq!(n, 12);
}

Rust 1.65(rustc --edition=2021)开始支持 let-else 语法(outer let),let-else 的变量作用域是所在 block:

  • let-else 的 else 子句是必须的,且不能返回,所以内部一般是 panic!;
use std::str::FromStr;

fn get_count_item(s: &str) -> (u64, &str) {
    let mut it = s.split(' ');

    // 如果匹配,count_str/item 可以在函数中使用。
    let (Some(count_str), Some(item)) = (it.next(), it.next()) else {
        panic!("Can't segment count item pair: '{s}'");
    };

    let Ok(count) = u64::from_str(count_str) else {
        panic!("Can't parse integer: '{count_str}'");
    };

    (count, item)
}

fn main() {
    assert_eq!(get_count_item("3 chairs"), (3, "chairs"));
}

// 对比:使用 match/if-let 的例子,count_str/item 只在内部有效
let (count_str, item) = match (it.next(), it.next()) {
    (Some(count_str), Some(item)) => (count_str, item),
    _ => panic!("Can't segment count item pair: '{s}'"),
};

// 变量析构
struct Pair(Box<i32>, Box<i32>);
impl Pair {
    fn destroy(self) {
        // self 的两个 Box 被转移到 first 和 second 变量,它们的 scope 是 destroy 函数体。
        let Pair(first, second) = self;
        println!("Destroying Pair({}, {})", first, second);
        // first 和 second 在函数返回时被 drop
    }
}

while 循环(true、false):

fn main() {
    let mut n = 1;
    while n < 101 {
        if n % 15 == 0 {
            println!("fizzbuzz");
        } else if n % 3 == 0 {
            println!("fizz");
        } else if n % 5 == 0 {
            println!("buzz");
        } else {
            println!("{}", n);
        }
        n += 1;
    }
}

while-let 用于消除 loop-match 循环模式:

while let _ = 5 {
    println!("Irrefutable patterns are always true");
    break;
}

// loop-match 循环
let mut optional = Some(0);
loop {
    match optional {
        Some(i) => {
            if i > 9 {
                println!("Greater than 9, quit!");
                optional = None;
            } else {
                println!("`i` is `{:?}`. Try again.", i);
                optional = Some(i + 1);
            }
        },
        _ => { break; }
    }
}

// 使用简化的 while-let 语句
let mut optional = Some(0);
while let Some(i) = optional {
    if i > 9 {
        println!("Greater than 9, quit!");
        optional = None;
    } else {
        println!("`i` is `{:?}`. Try again.", i);
        optional = Some(i + 1);
    }
}

for-in 用于迭代,迭代 item 变量也支持解构:

  1. for item in collect; item 为元素值;
  2. for item in &collect; item 为元素值引用 &T;
  3. for item in &mut collect; item 为元素值可变引用 &mut T;

a..b, a..=b, a.. 都是 RangeXX 语法糖(a 和 b 可以是表达式), 支持 for-in 迭代和 index 操作:

fn main() {
    for n in 1..=100 {
        if n == 100 {
            panic!("NEVER LET THIS RUN")
        }
    }
    println!("Success!");

    for number in (1..4).rev() {
        println!("{}!", number);
    }
}

// 范围可以是表达式
let end = 5;
let mut sum = 0;
for i in 1..(end + 1) {
    sum += i;
}

对于 array 的 into_iter() , 2021 和以前的版本有所变化:

  1. 2021 以前版本, 如 2018:for i in array.into_iter() 等效为 for i (&array).into_iter() , 迭代值 i 为 &T 类型;
  2. 2021 版本以后:for i in array.into_iter() 迭代值类型为数组元素本身类型;
fn main() {
    let a = [4, 3, 2, 1];
    // 2021 及以后 v 类型是元素本身,以前版本是 &T;
    for (i, v) in a.into_iter().enumerate() {
        println!("{i} {v}");
    }
}
rust-lang - 这篇文章属于一个选集。
§ 7: 本文

相关文章

1. 标识符和注释:identify/comment
·
Rust
Rust 标识符介绍
10. 泛型和特性:generic/trait
·
Rust
Rust 泛型和特性
11. 类型协变:type coercion
·
Rust
Rust 高级话题:子类型和类型协变
12. 迭代器:iterator
·
Rust
Rust 迭代器