跳过正文

流程控制:flow control

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

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

Rust 是表达式语言,程序 block 由 分号 结尾的 statement 组成。如果 expression 不以分号结尾,则它作为 block 的返回值,否则返回 unit type 值 ();

fn main() {
    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);
}

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

fn main() {
    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 {
        break 10; // loop break 返回值。
    }
};

循环支持嵌套,可以使用 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 中变量有效 scope 是 expression 右边的 block;

fn main() {
    // pattern 的元素数量必须与右边一致,解构后的变量 scope 是表达式右边的 block;
    if let (a, 1) = (2, 4) {
        println!("a: {a}")
    } else { // if let 不匹配的情况
        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);
}

match/if-let/while-let 绑定的变量只是表达式右边的 block 内部有效,一般还需要 outer let 表达式来返回值。Rust 1.65(rustc –edition=2021)开始支持 let-else 语法,let-else 的变量 scope 是所在 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 在函数返回时被释放
    }
}

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 没有 else 子句:

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 专用于迭代(for-in),有三种迭代方式:

  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 - 这篇文章属于一个选集。
§ 8: 本文

相关文章

不安全:unsafe
··824 字
Rust
Rust
借用:refer/borrow
··3127 字
Rust
Rust 引用类型和借用
函数、方法和闭包:function/method/closure
··7032 字
Rust
Rust 函数、方法和闭包
包和模块:package/crate/module
··2066 字
Rust
Rust 项目的包和模块组织结构