Rust基础语法之模式

73 阅读4分钟

Rust 的模式匹配如何与枚举、OptionResult 和 Box 等特性结合,提供强大而安全的控制流处理能力。这种模式匹配机制是 Rust 表达能力的重要组成部分,帮助开发者编写更清晰、更可靠的代码。

1. 枚举(enum)与模式匹配

  • 定义了 Message 枚举,包含多种不同类型的变体(单位变体、结构体变体、元组变体)
  • 使用 match 表达式对枚举变体进行模式匹配,根据不同变体执行不同操作
  • 包含了 Nested 变体,演示如何使用 Box 处理递归枚举(避免无限大小问题)

2. Option 枚举

  • Option<T> 是 Rust 标准库提供的枚举,用于表示一个值可能存在(Some(T))或不存在(None
  • find_even_number 函数返回 Option<i32>,找到偶数时返回 Some(num),否则返回 None
  • 展示了两种匹配方式:完整的 match 表达式和简化的 if let 语法

3. Result 枚举

  • Result<T, E> 用于表示操作可能成功(Ok(T))或失败(Err(E)
  • divide 函数返回 Result<f64, String>,成功时返回计算结果,失败时返回错误信息
  • 使用 match 匹配 Result 的两种结果,分别处理成功和失败的情况

4. Box 与递归结构

  • 定义了 LinkedList 枚举,使用 Box 实现递归结构(链表)
  • Box<LinkedList> 允许创建递归数据结构,因为 Box 是一个指针,有固定大小
  • 实现了链表的长度计算和打印功能,展示了如何通过模式匹配递归处理数据结构

模式匹配的核心特点

  • 穷尽性match 必须覆盖所有可能的情况,确保没有未处理的分支
  • 解构:可以直接从枚举变体中提取值(如 Message::Move { x, y } 提取 x 和 y)
  • 灵活性:支持多种匹配形式,从完整匹配到简化的 if let 语法
  • 安全性:编译时检查确保所有可能的情况都被处理,避免运行时错误

// 1. 定义一个复杂枚举,包含不同类型的变体
enum Message {
    Quit,
    Move { x: i32, y: i32 },
    Write(String),
    ChangeColor(i32, i32, i32),
    // 包含Box的递归枚举(需要Box来避免无限大小问题)
    Nested(Box<Message>),
}

// 为Message枚举实现方法
impl Message {
    fn call(&self) {
        // 对枚举进行模式匹配
        match self {
            Message::Quit => println!("收到退出消息"),
            Message::Move { x, y } => println!("移动到坐标: ({}, {})", x, y),
            Message::Write(text) => println!("收到消息: {}", text),
            Message::ChangeColor(r, g, b) => println!("改变颜色为 RGB({}, {}, {})", r, g, b),
            Message::Nested(inner_msg) => {
                println!("收到嵌套消息,正在处理内部消息...");
                inner_msg.call(); // 递归处理内部消息
            }
        }
    }
}

// 2. 使用Option枚举(Rust标准库提供)
// Option<T> 定义为: enum Option<T> { Some(T), None }
fn find_even_number(numbers: &[i32]) -> Option<i32> {
    for &num in numbers {
        if num % 2 == 0 {
            return Some(num); // 找到偶数,返回Some(值)
        }
    }
    None // 未找到偶数,返回None
}

// 3. 使用Result枚举(Rust标准库提供)
// Result<T, E> 定义为: enum Result<T, E> { Ok(T), Err(E) }
fn divide(a: f64, b: f64) -> Result<f64, String> {
    if b == 0.0 {
        Err("除数不能为零".to_string()) // 错误情况返回Err
    } else {
        Ok(a / b) // 成功情况返回Ok(结果)
    }
}

// 4. 结合Box和模式匹配处理递归结构
#[derive(Debug)]
enum LinkedList {
    Node(i32, Box<LinkedList>),
    Nil,
}

impl LinkedList {
    // 计算链表长度
    fn length(&self) -> usize {
        match self {
            LinkedList::Node(_, next) => 1 + next.length(),
            LinkedList::Nil => 0,
        }
    }
    
    // 打印链表内容
    fn print(&self) {
        match self {
            LinkedList::Node(value, next) => {
                print!("{} -> ", value);
                next.print();
            }
            LinkedList::Nil => println!("Nil"),
        }
    }
}

fn main() {
    // 演示枚举的模式匹配
    let messages = [
        Message::Quit,
        Message::Move { x: 10, y: 20 },
        Message::Write(String::from("Hello, Rust!")),
        Message::ChangeColor(255, 0, 0),
        Message::Nested(Box::new(Message::Write(String::from("这是嵌套消息")))),
    ];
    
    println!("=== 处理消息 ===");
    for msg in &messages {
        msg.call();
    }

    // 演示Option的模式匹配
    println!("\n=== 处理Option ===");
    let numbers = [1, 3, 5, 8, 9];
    let even_number = find_even_number(&numbers);
    
    // 完整匹配Option
    match even_number {
        Some(num) => println!("找到第一个偶数: {}", num),
        None => println!("没有找到偶数"),
    }
    
    // 使用if let简化匹配(只关心一种情况)
    if let Some(num) = even_number {
        println!("使用if let找到偶数: {}", num);
    }

    // 演示Result的模式匹配
    println!("\n=== 处理Result ===");
    let division_results = [
        divide(10.0, 2.0),
        divide(5.0, 0.0),
        divide(8.0, 3.0),
    ];
    
    for result in division_results {
        match result {
            Ok(value) => println!("除法结果: {:.2}", value),
            Err(e) => println!("除法错误: {}", e),
        }
    }
    
    // 演示结合Box的链表模式匹配
    println!("\n=== 处理链表 ===");
    // 构建链表: 1 -> 2 -> 3 -> Nil
    let list = LinkedList::Node(
        1,
        Box::new(LinkedList::Node(
            2,
            Box::new(LinkedList::Node(3, Box::new(LinkedList::Nil))),
        )),
    );
    
    println!("链表内容:");
    list.print();
    println!("链表长度: {}", list.length());
    
    // 匹配链表的不同情况
    match &list {
        LinkedList::Node(first, _) => println!("链表第一个元素: {}", first),
        LinkedList::Nil => println!("这是一个空链表"),
    }
}