从零开始学Rust:枚举(enum)与模式匹配核心机制

枚举类型本质

Rust的枚举(enum)本质上是一种 代数数据类型 (Algebraic Data Type),与函数式语言(F#OCaml/Haskell)中的实现类似。枚举允许定义包含不同数据类型的 变体(Variant),每个变体可携带不同类型和数量的关联数据。

Rust's enums are most similar to algebraic data types in functional languages, such as F#, OCaml, and Haskell.

There's another advantage to using an enum rather than a struct: each variant can have different types and amounts of associated data.

rust 复制代码
fn main() {
    enum IpAddr {
        V4(String),
        V6(String),
    }
    let home = IpAddr::V4(String::from("127.0.0.1"));
    let loopback = IpAddr::V6(String::from("::1"));
}
rust 复制代码
fn main() {
    enum IpAddr {
        V4(u8, u8, u8, u8),
        V6(String),
    }
    let home = IpAddr::V4(127, 0, 0, 1);
    let loopback = IpAddr::V6(String::from("::1"));
}

Option枚举与空值安全(control flow operator)

rust 复制代码
enum Option<T> {
    Some(T),
    None,
}
  • Rust通过Option<T>枚举优雅处理空值问题,包含Some(T)None两个变体

  • 必须显式处理Option类型,避免 "Null References: The Billion Dollar Mistake"(Tony Hoare提出的空引用问题:"十亿美元错误")

    I call it my billion-dollar mistake. At that time, I was designing the first comprehensive type system for references in an object-oriented language. My goal was to ensure that all use of references should be absolutely safe, with checking performed automatically by the compiler. But I couldn't resist the temptation to put in a null reference, simply because it was so easy to implement. This has led to innumerable errors, vulnerabilities, and system crashes, which have probably caused a billion dollars of pain and damage in the last forty years.

  • Option类型保证不会为null,极大提高代码安全性

    rust 复制代码
    fn main() {
        let some_number = Some(5);
        let some_string = Some("a string");
        let absent_number: Option<i32> = None;
    }

You have to convert an Option<T> to a T before you can perform T operations with it. Generally, this helps catch one of the most common issues with null: assuming that something isn't null when it actually is.

Not having to worry about incorrectly assuming a not-null value helps you to be more confident in your code. In order to have a value that can possibly be null, you must explicitly opt in by making the type of that value Option<T>. Then, when you use that value, you are required to explicitly handle the case when the value is null. Everywhere that a value has a type that isn't an Option<T>, you can safely assume that the value isn't null. This was a deliberate design decision for Rust to limit null's pervasiveness and increase the safety of Rust code.

模式匹配机制

  • match表达式:

    • 必须穷尽所有可能模式(exhaustive matching)
    • 每个分支包含模式(pattern)和执行代码
    • 可解构枚举值获取内部数据
    rust 复制代码
    enum Coin {
        Penny,
        Nickel,
        Dime,
        Quarter,
    }
    
    fn value_in_cents(coin: Coin) -> u8 {
        match coin {
            Coin::Penny => 1,
            Coin::Nickel => 5,
            Coin::Dime => 10,
            Coin::Quarter => 25,
        }
    }

    Next are the match arms. An arm has two parts: a pattern and some code.

    rust 复制代码
    enum Coin {
        Penny,
        Nickel,
        Dime,
        Quarter,
    }
    
    fn value_in_cents(coin: Coin) -> u8 {
        match coin {
            Coin::Penny => {
                println!("Lucky penny!");
                1
            }
            Coin::Nickel => 5,
            Coin::Dime => 10,
            Coin::Quarter => 25,
        }
    }

    50 State Quarters

    rust 复制代码
    #[derive(Debug)]
    enum UsState {
        Alabama,
        Alaska,
        // --snip--
    }
    
    enum Coin {
        Penny,
        Nickel,
        Dime,
        Quarter(UsState),
    }
    
    fn value_in_cents(coin: Coin) -> u8 {
        match coin {
            Coin::Penny => 1,
            Coin::Nickel => 5,
            Coin::Dime => 10,
            Coin::Quarter(state) => {
                println!("State quarter from {:?}!", state);
                25
            }
        }
    }
    
    fn main() {
        value_in_cents(Coin::Quarter(UsState::Alaska));
    }
  • 通配模式:

    • _匹配所有未指定情况
    • 常用()单位值表示不执行操作
  • if let语法糖:

    • 简化单一模式匹配场景
    • 牺牲穷尽性检查换取代码简洁性
    • 等价于只处理一个分支的match表达式

Matches in Rust are exhaustive : we must exhaust every last possibility in order for the code to be valid. Especially in the case of Option<T>, when Rust prevents us from forgetting to explicitly handle the None case, it protects us from assuming that we have a value when we might have null, thus making the billion-dollar mistake discussed earlier impossible.

By putting it after our other arms, the _ will match all the possible cases that aren't specified before it. The () is just the unit value, so nothing will happen in the _ case. As a result, we can say that we want to do nothing for all the possible values that we don't list before the _ placeholder.

rust 复制代码
let some_u8_value = 0u8;
   match some_u8_value {
       1 => println!("one"),
       3 => println!("three"),
       5 => println!("five"),
       7 => println!("seven"),
       _ => (),
   }

Concise Control Flow with if let

rust 复制代码
let some_u8_value = Some(0u8);
match some_u8_value {
    Some(3) => println!("three"),
    _ => (),
}
rust 复制代码
if let Some(3) = some_u8_value {
    println!("three");
}

Choosing between match and if let depends on what you're doing in your particular situation and whether gaining conciseness is an appropriate trade-off for losing exhaustive checking.

In other words, you can think of if let as syntax sugar for a match that runs code when the value matches one pattern and then ignores all other values.

rust 复制代码
let mut count = 0;
match coin {
    Coin::Quarter(state) => println!("State quarter from {:?}!", state),
    _ => count += 1,
}

If you have a situation in which your program has logic that is too verbose to express using a match, remember that if let is in your Rust toolbox as well.

rust 复制代码
let mut count = 0;
if let Coin::Quarter(state) = coin {
    println!("State quarter from {:?}!", state);
} else {
    count += 1;
}
相关推荐
间彧几秒前
Java单例模式:饿汉式与懒汉式实现详解
后端
道可到2 分钟前
百度面试真题 Java 面试通关笔记 04 |JMM 与 Happens-Before并发正确性的基石(面试可复述版)
java·后端·面试
威风的虫12 分钟前
JavaScript中的axios
开发语言·javascript·ecmascript
老赵的博客16 分钟前
c++ 是静态编译语言
开发语言·c++
Terio_my17 分钟前
Python制作12306查票工具:从零构建铁路购票信息查询系统
开发语言·python·microsoft
Ray6618 分钟前
guide-rpc-framework笔记
后端
37手游后端团队20 分钟前
Claude Code Review:让AI审核更懂你的代码
人工智能·后端·ai编程
消失的旧时光-194340 分钟前
Kotlin when 用法完整分享
android·开发语言·kotlin
万粉变现经纪人40 分钟前
如何解决 pip install -r requirements.txt 约束文件 constraints.txt 仅允许固定版本(未锁定报错)问题
开发语言·python·r语言·django·beautifulsoup·pandas·pip
长安不见1 小时前
解锁网络性能优化利器HTTP/2C
后端