用户工具

站点工具


rust:第四章控制流

第四章 控制流

4.1 if表达式

基础if语法

let number = 6;
 
if number < 5 {
    println!("条件为真");
} else {
    println!("条件为假");
}

多条件判断

let number = 6;
 
if number % 4 == 0 {
    println!("能被4整除");
} else if number % 3 == 0 {
    println!("能被3整除");
} else if number % 2 == 0 {
    println!("能被2整除");
} else {
    println!("不能被4、3或2整除");
}

if作为表达式

Rust的if是一个表达式,可以返回值:

let condition = true;
let number = if condition { 5 } else { 6 };
 
println!("number的值是:{}", number);  // 5

重要规则:if分支返回的类型必须相同。

// 错误示例
let number = if condition { 5 } else { "six" };  // 编译错误!

4.2 循环

Rust有三种循环:loop、while和for。

loop无限循环

loop {
    println!("永远循环!");
    // 使用break退出
}

带返回值的loop:

let mut counter = 0;
 
let result = loop {
    counter += 1;
 
    if counter == 10 {
        break counter * 2;  // 返回值
    }
};
 
println!("结果:{}", result);  // 20

loop标签:

let mut count = 0;
 
'counting_up: loop {
    println!("count = {}", count);
    let mut remaining = 10;
 
    loop {
        println!("remaining = {}", remaining);
        if remaining == 9 {
            break;  // 退出内层循环
        }
        if count == 2 {
            break 'counting_up;  // 退出外层循环
        }
        remaining -= 1;
    }
 
    count += 1;
}
 
println!("结束 count = {}", count);

while条件循环

let mut number = 3;
 
while number != 0 {
    println!("{}!", number);
    number -= 1;
}
 
println!("发射!");

用while遍历数组:

let a = [10, 20, 30, 40, 50];
let mut index = 0;
 
while index < 5 {
    println!("值为:{}", a[index]);
    index += 1;
}

for遍历

遍历集合:

let a = [10, 20, 30, 40, 50];
 
for element in a.iter() {
    println!("值为:{}", element);
}

使用Range:

// 1到3(不包括4)
for number in 1..4 {
    println!("{}!", number);
}
 
// 1到4(包括4)
for number in 1..=4 {
    println!("{}!", number);
}
 
// 反向
for number in (1..4).rev() {
    println!("{}!", number);
}

带索引的遍历:

let v = vec!['a', 'b', 'c'];
 
for (index, value) in v.iter().enumerate() {
    println!("{} 在索引 {}", value, index);
}

4.3 match表达式

match是Rust强大的模式匹配结构,类似C的switch但功能更强大。

基础match

let number = 7;
 
match number {
    1 => println!("一"),
    2 => println!("二"),
    3 => println!("三"),
    4 => println!("四"),
    5 => println!("五"),
    _ => println!("其他"),
}

match必须穷尽(exhaustive):

let number = 7;
 
match number {
    1 => println!("一"),
    // 错误!缺少其他情况的处理
}

匹配多个模式

let number = 1;
 
match number {
    1 | 2 => println!("一或二"),
    3..=7 => println!("三到七之间"),
    _ => println!("其他"),
}

match返回值

let number = 2;
 
let result = match number {
    1 => "一",
    2 => "二",
    3 => "三",
    _ => "其他",
};
 
println!("结果是:{}", result);

4.4 模式匹配详解

解构元组

let point = (3, 5);
 
match point {
    (0, 0) => println!("原点"),
    (x, 0) => println!("x轴上,x = {}", x),
    (0, y) => println!("y轴上,y = {}", y),
    (x, y) => println!("点 ({}, {})", x, y),
}

解构结构体

struct Point {
    x: i32,
    y: i32,
}
 
let p = Point { x: 0, y: 7 };
 
match p {
    Point { x, y: 0 } => println!("在x轴上,x = {}", x),
    Point { x: 0, y } => println!("在y轴上,y = {}", y),
    Point { x, y } => println!("点 ({}, {})", x, y),
}

使用..忽略剩余字段:

struct Point3D {
    x: i32,
    y: i32,
    z: i32,
}
 
let p = Point3D { x: 1, y: 2, z: 3 };
 
match p {
    Point3D { x, .. } => println!("x是{}", x),
}

解构枚举

enum Message {
    Quit,
    Move { x: i32, y: i32 },
    Write(String),
    ChangeColor(i32, i32, i32),
}
 
let msg = Message::ChangeColor(0, 160, 255);
 
match msg {
    Message::Quit => {
        println!("Quit");
    }
    Message::Move { x, y } => {
        println!("移动到 x: {}, y: {}", x, y);
    }
    Message::Write(text) => {
        println!("文本消息:{}", text);
    }
    Message::ChangeColor(r, g, b) => {
        println!("改变颜色为 R: {}, G: {}, B: {}", r, g, b);
    }
}

使用if let简化

对于只关心一个模式的情况:

let some_value = Some(3);
 
// match写法
match some_value {
    Some(3) => println!("是三"),
    _ => (),
}
 
// if let写法(更简洁)
if let Some(3) = some_value {
    println!("是三");
}

if let带else:

if let Some(3) = some_value {
    println!("是三");
} else {
    println!("不是三");
}

while let

let mut stack = Vec::new();
stack.push(1);
stack.push(2);
stack.push(3);
 
while let Some(top) = stack.pop() {
    println!("弹出:{}", top);
}

4.5 绑定与守卫

@绑定

@运算符允许在测试模式的同时创建变量:

enum Message {
    Hello { id: i32 },
}
 
let msg = Message::Hello { id: 5 };
 
match msg {
    Message::Hello { id: id_variable @ 3..=7 } => {
        println!("id在范围内:{}", id_variable);
    }
    Message::Hello { id: 10..=12 } => {
        println!("id在10到12之间,但没有绑定");
    }
    Message::Hello { id } => {
        println!("其他id:{}", id);
    }
}

匹配守卫

let num = Some(4);
 
match num {
    Some(x) if x < 5 => println!("小于5:{}", x),
    Some(x) => println!("{}", x),
    None => (),
}

多个模式的守卫:

let x = 4;
let y = false;
 
match x {
    4 | 5 | 6 if y => println!("yes"),
    _ => println!("no"),
}

4.6 模式匹配的更多特性

忽略值

使用_忽略整个值:

fn foo(_: i32, y: i32) {
    println!("y = {}", y);
}
 
foo(3, 4);

使用_忽略部分值:

let mut setting_value = Some(5);
let new_setting_value = Some(10);
 
match (setting_value, new_setting_value) {
    (Some(_), Some(_)) => {
        println!("不能覆盖已有值");
    }
    _ => {
        setting_value = new_setting_value;
    }
}

使用以_开头的名称:

let s = Some(String::from("Hello!"));
 
if let Some(_s) = s {
    println!("找到了字符串");
}
 
// println!("{:?}", s);  // 错误!s已被移动

使用_则不会移动:

if let Some(_) = s {
    println!("找到了字符串");
}
 
println!("{:?}", s);  // 正确!

练习题

练习题4.1:猜数字游戏

use std::io;
 
fn main() {
    let secret_number = 42;
 
    loop {
        println!("请输入你的猜测:");
 
        let mut guess = String::new();
        io::stdin()
            .read_line(&mut guess)
            .expect("读取失败");
 
        let guess: i32 = match guess.trim().parse() {
            Ok(num) => num,
            Err(_) => {
                println!("请输入数字!");
                continue;
            }
        };
 
        match guess.cmp(&secret_number) {
            std::cmp::Ordering::Less => println!("太小了!"),
            std::cmp::Ordering::Greater => println!("太大了!"),
            std::cmp::Ordering::Equal => {
                println!("猜对了!");
                break;
            }
        }
    }
}

练习题4.2:FizzBuzz

fn main() {
    for n in 1..=100 {
        match (n % 3, n % 5) {
            (0, 0) => println!("FizzBuzz"),
            (0, _) => println!("Fizz"),
            (_, 0) => println!("Buzz"),
            _ => println!("{}", n),
        }
    }
}

练习题4.3:简单计算器

fn calculate(a: f64, b: f64, op: char) -> Option<f64> {
    match op {
        '+' => Some(a + b),
        '-' => Some(a - b),
        '*' => Some(a * b),
        '/' => if b != 0.0 { Some(a / b) } else { None },
        _ => None,
    }
}
 
fn main() {
    let a = 10.0;
    let b = 3.0;
    let op = '*';
 
    match calculate(a, b, op) {
        Some(result) => println!("{} {} {} = {}", a, op, b, result),
        None => println!("无效操作或除零错误"),
    }
}

练习题4.4:数字转中文

fn number_to_chinese(n: u32) -> String {
    match n {
        0 => "零".to_string(),
        1 => "一".to_string(),
        2 => "二".to_string(),
        3 => "三".to_string(),
        4 => "四".to_string(),
        5 => "五".to_string(),
        6 => "六".to_string(),
        7 => "七".to_string(),
        8 => "八".to_string(),
        9 => "九".to_string(),
        10 => "十".to_string(),
        _ => n.to_string(),
    }
}
 
fn main() {
    for i in 0..=10 {
        println!("{} -> {}", i, number_to_chinese(i));
    }
}

本章小结

本章学习了Rust的控制流结构:

  • if表达式:条件判断,可以作为表达式返回值
  • loop:无限循环,可以返回值,支持标签跳出
  • while:条件循环
  • for:遍历集合或Range,最常用
  • match:强大的模式匹配,必须穷尽所有情况
  • 模式匹配:解构元组、结构体、枚举
  • if let/while let:简化单模式匹配
  • 匹配守卫:添加额外条件
  • @绑定:测试模式同时绑定值

控制流是编程的基础,Rust的模式匹配系统特别强大,建议多加练习。

rust/第四章控制流.txt · 最后更改: 127.0.0.1