12·复合类型入门

模式匹配 match

模式匹配 match

学习目标

  1. 掌握 match 表达式的完整用法
  2. 理解穷尽性(exhaustive)
  3. 掌握各种模式语法
  4. 掌握 if letwhile let

核心概念

基本 match

fn main() {
    let number = 3;

    match number {
        1 => println!("一"),
        2 => println!("二"),
        3 => println!("三"),
        _ => println!("其他"),  // _ 是通配符,匹配所有
    }
}

匹配枚举

enum Coin {
    Penny,
    Nickel,
    Dime,
    Quarter,
}

fn value_in_cents(coin: &Coin) -> u32 {
    match coin {
        Coin::Penny => {
            println!("幸运便士!");
            1
        }
        Coin::Nickel => 5,
        Coin::Dime => 10,
        Coin::Quarter => 25,
    }
}

绑定值

enum Shape {
    Circle(f64),
    Rectangle(f64, f64),
}

fn describe(shape: &Shape) -> String {
    match shape {
        Shape::Circle(r) => format!("圆形,半径 {}", r),
        Shape::Rectangle(w, h) => format!("矩形,{}×{}", w, h),
    }
}

匹配守卫(match guard)

fn main() {
    let x = 4;

    match x {
        n if n < 0 => println!("负数"),
        n if n == 0 => println!("零"),
        n if n % 2 == 0 => println!("{} 是偶数", n),
        n => println!("{} 是奇数", n),
    }
}

多模式

fn main() {
    let x = 1;

    match x {
        1 | 2 => println!("一或二"),    // | 表示或
        3..=9 => println!("三到九"),     // 范围
        _ => println!("其他"),
    }
}

fn main() {
    let c = 'z';
    match c {
        'a'..='j' => println!("前半"),
        'k'..='z' => println!("后半"),
        _ => println!("其他"),
    }
}

解构结构体

struct Point {
    x: i32,
    y: i32,
}

fn main() {
    let p = Point { x: 0, y: 7 };

    match p {
        Point { x, y: 0 } => println!("在 x 轴上: {}", x),
        Point { x: 0, y } => println!("在 y 轴上: {}", y),
        Point { x, y } => println!("({},{})", x, y),
    }
}

解构嵌套

enum Color {
    Rgb(u8, u8, u8),
    Hsl(u16, u8, u8),
}

enum Message {
    Quit,
    Color(Color),
}

fn main() {
    let msg = Message::Color(Color::Rgb(255, 128, 0));

    match msg {
        Message::Color(Color::Rgb(r, g, b)) => {
            println!("RGB({}, {}, {})", r, g, b);
        }
        Message::Color(Color::Hsl(h, s, l)) => {
            println!("HSL({}, {}, {})", h, s, l);
        }
        Message::Quit => println!("退出"),
    }
}

忽略值

fn main() {
    let point = (1, 2, 3);

    match point {
        (0, _, _) => println!("x 是 0"),
        (_, 0, _) => println!("y 是 0"),
        (_, _, 0) => println!("z 是 0"),
        _ => println!("没有零"),
    }

    // 忽略剩余字段
    let (_, y, _) = point;
    println!("y = {}", y);
}

if let(简写)

fn main() {
    let config_max: Option<u8> = Some(3);

    // 完整 match
    match config_max {
        Some(max) => println!("最大值: {}", max),
        _ => (),  // 不关心 None
    }

    // if let 简写
    if let Some(max) = config_max {
        println!("最大值: {}", max);
    }

    // if let + else
    if let Some(max) = config_max {
        println!("最大值: {}", max);
    } else {
        println!("没有设置最大值");
    }
}

while let

fn main() {
    let mut stack = vec![1, 2, 3, 4, 5];

    // pop 返回 Option<T>
    while let Some(top) = stack.pop() {
        println!("{}", top);
    }
    // 输出: 5, 4, 3, 2, 1
}

let else(Rust 1.65+)

fn get_count(item: &str) -> Option<u32> {
    match item {
        "apple" => Some(5),
        "banana" => Some(3),
        _ => None,
    }
}

fn main() {
    let item = "apple";

    // let else:不匹配时提前返回
    let Some(count) = get_count(item) else {
        println!("未知物品");
        return;
    };
    println!("数量: {}", count);
}

实践练习

练习 1:扑克牌

#[derive(Debug)]
enum Suit {
    Hearts,
    Diamonds,
    Clubs,
    Spades,
}

#[derive(Debug)]
enum Rank {
    Ace,
    Number(u8),  // 2-10
    Jack,
    Queen,
    King,
}

fn describe_card(suit: &Suit, rank: &Rank) -> String {
    let suit_str = match suit {
        Suit::Hearts => "♥",
        Suit::Diamonds => "♦",
        Suit::Clubs => "♣",
        Suit::Spades => "♠",
    };
    let rank_str = match rank {
        Rank::Ace => String::from("A"),
        Rank::Number(n) => n.to_string(),
        Rank::Jack => String::from("J"),
        Rank::Queen => String::from("Q"),
        Rank::King => String::from("K"),
    };
    format!("{}{}", suit_str, rank_str)
}

fn main() {
    let hand = [
        (Suit::Hearts, Rank::Ace),
        (Suit::Spades, Rank::King),
        (Suit::Diamonds, Rank::Number(7)),
    ];
    for (suit, rank) in &hand {
        println!("{}", describe_card(suit, rank));
    }
}

练习 2:简单计算器

enum Op {
    Add,
    Sub,
    Mul,
    Div,
}

fn calculate(a: f64, op: &Op, b: f64) -> Option<f64> {
    match op {
        Op::Add => Some(a + b),
        Op::Sub => Some(a - b),
        Op::Mul => Some(a * b),
        Op::Div => {
            if b == 0.0 { None } else { Some(a / b) }
        }
    }
}

fn main() {
    let ops = [Op::Add, Op::Sub, Op::Mul, Op::Div];
    for op in &ops {
        match calculate(10.0, op, 3.0) {
            Some(result) => println!("结果: {}", result),
            None => println!("错误: 除以零"),
        }
    }
}

常见错误

1. 非穷尽匹配

let x: i32 = 5;
match x {
    1 => println!("一"),
    2 => println!("二"),
    // ❌ 缺少 _ 分支,编译器要求穷尽
}

2. 忘记绑定变量

let some_value = Some(5);
match some_value {
    Some(_) => println!("有值"),  // _ 忽略了值
    // 想用值的话要 Some(x)
    None => println!("无"),
}

小结

语法用途
match x { ... }穷尽匹配
_通配符
|多模式
..=范围模式
if let只关心一个分支
while let循环直到不匹配
let else不匹配则提前返回

练习编辑器

rust
Loading...