【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博客

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

目录


🎯定义枚举

枚举:

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

如:

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

enum IpAddrKind {
    V4,
    V6,
}

枚举值:

    let four = IpAddrKind::V4;
    let six = IpAddrKind::V6;

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

fn route(ip_kind: IpAddrKind) {}

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

    route(IpAddrKind::V4);
    route(IpAddrKind::V6);

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

    enum IpAddr {
        V4(String),
        V6(String),
    }

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

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

优点:

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

如:

    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

struct Ipv4Addr {
    // --snip--
}

struct Ipv6Addr {
    // --snip--
}

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

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

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

为枚举定义方法:

例子:

    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>

enum Option<T> {
    None,
    Some(T),
}

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

        —Option<T>

        —Some(T)

        —None

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

例子:

    let some_number = Some(5);
    let some_char = Some('e');

    let absent_number: Option<i32> = None;

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

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

如:

    let x: i8 = 5;
    let y: Option<i8> = Some(5);

    let sum = x + y;

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

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

🎯控制流运算符-match

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

例子:

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

 🥽绑定值得模式:

例子:

#[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
        }
    }
}

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

🥽匹配Option<T>

    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匹配必须穷举所有的可能

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

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

🥽通配符

    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 强制要求的穷尽性检查。match 和 if let 之间的选择依赖特定的环境以及增加简洁度和失去穷尽性检查的权衡取舍。

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

等价于

    let config_max = Some(3u8);
    match config_max {
        Some(max) => println!("The maximum is configured to be {}", max),
        _ => (),
    }

版权声明:本文为博主作者:Y小夜原创文章,版权归属原作者,如果侵权,请联系我们删除!

原文链接:https://blog.csdn.net/shsjssnn/article/details/136079854

共计人评分,平均

到目前为止还没有投票!成为第一位评论此文章。

(0)
社会演员多的头像社会演员多普通用户
上一篇 2024年4月1日
下一篇 2024年4月1日

相关推荐