【Rust】——枚举与模式匹配

🎃个人专栏:

🐬 算法设计与分析:算法设计与分析_IT闫的博客-CSDN博客

🐳Java基础:Java基础_IT闫的博客-CSDN博客

🐋c语言:c语言_IT闫的博客-CSDN博客

🐟MySQL:数据结构_IT闫的博客-CSDN博客

🐠数据结构:​​​​​​数据结构_IT闫的博客-CSDN博客

💎C++:C++_IT闫的博客-CSDN博客

🥽C51单片机:C51单片机(STC89C516)_IT闫的博客-CSDN博客

💻基于HTML5的网页设计及应用:基于HTML5的网页设计及应用_IT闫的博客-CSDN博客​​​​​​

🥏python:python_IT闫的博客-CSDN博客

🐠离散数学:离散数学_IT闫的博客-CSDN博客

​​​​​​🥽Linux:​​​​Linux_Y小夜的博客-CSDN博客

🚝Rust:Rust_Y小夜的博客-CSDN博客

欢迎收看,希望对大家有用!

目录

🎯定义枚举

🎯Option枚举

🥽类似Null概念的枚举---Option

🎯控制流运算符-match

🥽绑定值得模式:

🥽匹配Option

🥽match匹配必须穷举所有的可能

🥽通配符

[🎯if let](#🎯if let)


🎯定义枚举

枚举:

允许我们列举所有可能的值来定义一个类型。

如:

定义一个 IpAddrKind 枚举来表现这个概念并列出可能的 IP 地址类型,V4V6。这被称为枚举的 成员variants):

rust 复制代码
enum IpAddrKind {
    V4,
    V6,
}

枚举值:

rust 复制代码
    let four = IpAddrKind::V4;
    let six = IpAddrKind::V6;

注意枚举的成员位于其标识符的命名空间中,并使用两个冒号分开。这么设计的益处是现在 IpAddrKind::V4IpAddrKind::V6 都是 IpAddrKind 类型的。

rust 复制代码
fn route(ip_kind: IpAddrKind) {}

现在可以使用任一成员来调用这个函数:

rust 复制代码
    route(IpAddrKind::V4);
    route(IpAddrKind::V6);

将数据附加到枚举的变体中:

rust 复制代码
    enum IpAddr {
        V4(String),
        V6(String),
    }

    let home = IpAddr::V4(String::from("127.0.0.1"));

    let loopback = IpAddr::V6(String::from("::1"));

优点:

  • 直接将数据附加到枚举的每个成员上,这样就不需要一个额外的结构体
  • 每个成员可以处理不同类型和数量的数据。

如:

rust 复制代码
    enum IpAddr {
        V4(u8, u8, u8, u8),
        V6(String),
    }

    let home = IpAddr::V4(127, 0, 0, 1);

    let loopback = IpAddr::V6(String::from("::1"));

标准库中的IpAddr

rust 复制代码
struct Ipv4Addr {
    // --snip--
}

struct Ipv6Addr {
    // --snip--
}

enum IpAddr {
    V4(Ipv4Addr),
    V6(Ipv6Addr),
}

枚举成员中内嵌了多种多样的类型:

rust 复制代码
enum Message {
    Quit,
    Move { x: i32, y: i32 },
    Write(String),
    ChangeColor(i32, i32, i32),
}
  • Quit 没有关联任何数据。
  • Move 类似结构体包含命名字段。
  • Write 包含单独一个 String
  • ChangeColor 包含三个 i32

为枚举定义方法:

例子:

rust 复制代码
    impl Message {
        fn call(&self) {
            // 在这里定义方法体
        }
    }

    let m = Message::Write(String::from("hello"));
    m.call();

🎯Option枚举

  • Option 是标准库定义的另一个枚举。
  • 在Prelude(预导入模块中)
  • 描述了:某个可能存在(某种类型)或不存在的情况。

Rust 并没有很多其他语言中有的空值功能。空值Null )是一个值,它代表没有值。

  • Null引用:The Billion Dollar Mistake
  • Null的问题在于:当尝试像使用非Null值那样使用Null值的时候,就会引起某种错误。
  • Null的概念还是有用的,因某种原因变为无效或缺失的值。

🥽类似Null概念的枚举---Option<T>

rust 复制代码
enum Option<T> {
    None,
    Some(T),
}

它包括在Prelude(与导入模块)中。可直接使用:

---Option<T>

---Some(T)

---None

可以不需要 Option:: 前缀来直接使用。

例子:

rust 复制代码
    let some_number = Some(5);
    let some_char = Some('e');

    let absent_number: Option<i32> = None;

Rust 需要我们指定 Option 整体的类型,因为编译器只通过 None 值无法推断出 Some 成员保存的值的类型。这里我们告诉 Rust 希望 absent_numberOption<i32> 类型的。

简而言之,因为 Option<T>T(这里 T 可以是任何类型)是不同的类型,编译器不允许像一个肯定有效的值那样使用 Option<T>

如:

rust 复制代码
    let x: i8 = 5;
    let y: Option<i8> = Some(5);

    let sum = x + y;

会出现类型不匹配的错误。

若想使用Option<T>中的T,必须将它转化为T。

🎯控制流运算符-match

  • 我们将一个值与一系列的模式相比较,并根据相匹配的模式执行相应代码。
  • 模式可由字面值、变量、通配符和许多其他内容构成。

例子:

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,
    }
}

🥽绑定值得模式:

例子:

rust 复制代码
#[derive(Debug)] // 这样可以立刻看到州的名称
enum UsState {
    Alabama,
    Alaska,
    // --snip--
}

enum Coin {
    Penny,
    Nickel,
    Dime,
    Quarter(UsState),
}
rust 复制代码
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
        }
    }
}

在这些代码的匹配表达式中,我们在匹配 Coin::Quarter 成员的分支的模式中增加了一个叫做 state 的变量。当匹配到 Coin::Quarter 时,变量 state 将会绑定 25 美分硬币所对应州的值。接着在那个分支的代码中使用 state。

🥽匹配Option<T>

rust 复制代码
    fn plus_one(x: Option<i32>) -> Option<i32> {
        match x {
            None => None,
            Some(i) => Some(i + 1),
        }
    }

    let five = Some(5);
    let six = plus_one(five);
    let none = plus_one(None);

比如我们想要编写一个函数,它获取一个 Option<i32> ,如果其中含有一个值,将其加一。如果其中没有值,函数应该返回 None 值,而不尝试执行任何操作。

🥽match匹配必须穷举所有的可能

rust 复制代码
    fn plus_one(x: Option<i32>) -> Option<i32> {
        match x {
            Some(i) => Some(i + 1),
        }
    }

没有处理 None 的情况,所以这些代码会造成一个 bug

🥽通配符

rust 复制代码
    let dice_roll = 9;
    match dice_roll {
        3 => add_fancy_hat(),
        7 => remove_fancy_hat(),
        _ => (),
    }

    fn add_fancy_hat() {}
    fn remove_fancy_hat() {}

如果你掷出 3 或 7 以外的值,你的回合将无事发生。

🎯if let

if let 语法获取通过等号分隔的一个模式和一个表达式。它的工作方式与 match 相同,这里的表达式对应 match 而模式则对应第一个分支。

但是 ,这样会失去 match 强制要求的穷尽性检查。matchif let 之间的选择依赖特定的环境以及增加简洁度和失去穷尽性检查的权衡取舍。

rust 复制代码
    let config_max = Some(3u8);
    if let Some(max) = config_max {
        println!("The maximum is configured to be {}", max);
    }

等价于

rust 复制代码
    let config_max = Some(3u8);
    match config_max {
        Some(max) => println!("The maximum is configured to be {}", max),
        _ => (),
    }
相关推荐
一点媛艺2 小时前
Kotlin函数由易到难
开发语言·python·kotlin
姑苏风2 小时前
《Kotlin实战》-附录
android·开发语言·kotlin
奋斗的小花生3 小时前
c++ 多态性
开发语言·c++
魔道不误砍柴功3 小时前
Java 中如何巧妙应用 Function 让方法复用性更强
java·开发语言·python
NiNg_1_2343 小时前
SpringBoot整合SpringSecurity实现密码加密解密、登录认证退出功能
java·spring boot·后端
闲晨3 小时前
C++ 继承:代码传承的魔法棒,开启奇幻编程之旅
java·c语言·开发语言·c++·经验分享
老猿讲编程4 小时前
一个例子来说明Ada语言的实时性支持
开发语言·ada
Chrikk5 小时前
Go-性能调优实战案例
开发语言·后端·golang
幼儿园老大*5 小时前
Go的环境搭建以及GoLand安装教程
开发语言·经验分享·后端·golang·go
canyuemanyue5 小时前
go语言连续监控事件并回调处理
开发语言·后端·golang