Rust枚举与模式匹配

简介: Rust枚举与模式匹配
枚举enum是一种自定义类型。其次,Rust中没有Null,但它通过枚举来实现了Null相同的功能,这个枚举类就是Option\<T>,并且比其他语言更加安全。Rust中不支持switch,但Rust提供了一种用于穷举的控制流运算符——match。

Rust枚举与模式匹配

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

定义枚举

IP地址:IPv4,IPv6

enum IpAddrKind {
    V4,
    V6,
}

枚举的变体的取值:

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

枚举的变体都位于标识符的命名空间下,使用::符号进行分隔。

#[derive(Debug)]
enum IpAddrKind {
    V4,
    V6,
}
fn main() {
    let four = IpAddrKind::V4;
    let six = IpAddrKind::V6;

    println!("{:?},{:?}", four, six); //V4,V6
    
    route(four);
    route(six);

    route(IpAddrKind::V4);
}

fn route(ip_kind: IpAddrKind) {}

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

枚举的变体:指枚举中的“value”

现在我们希望能在看到ip的类型同时能够看到ip地址的示例。

通过之前的学习,我们可能会联想到将Struct中key的类型声明为枚举类型,让Struct中的address作为一个v4或者v6的值的示例。

enum IpAddrKind {
    V4,
    V6,
}

struct IpAddr {
    kind: IpAddrKind,
    address: String,
}
fn main() {
    let home = IpAddr {
        kind: IpAddrKind::V4,
        address: String::from("127.0.0.1"),
    };

    let loopback = IpAddr {
        kind: IpAddrKind::V6,
        address: String::from("::1"),
    };
}

但我们可以使用value(type)的形式来声明

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

优点:

  • 不需要额外使用Struct
  • 每个变体可以拥有不同的类型以及关联的数据量

例如:

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

一个例子:

#[derive(Debug)]
enum IpAddrKind {
    V4(u8, u8, u8, u8),
    V6(String),
}

fn main() {
    let home = IpAddrKind::V4(127, 0, 0, 1);
    let loopback = IpAddrKind::V6(String::from("::1"));

    println!("{:?},{:?}", home, loopback); //V4(127, 0, 0, 1),V6("::1")
}

标准库中的IpAddr

在标准库中也有IpAddr这个枚举类,我们可以看到v4和v6的数据类型为Struct。

struct Ipv4Addr{
    //...
}

struct Ipv6Addr{
    //...
}

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

事实上,枚举的变体中嵌入任何类型的数据(甚至是另一种枚举类型):

enum Message {
    Quit,
    Move { x: i32, y: i32 },
    Write(String),
    ChangeColor(i32, i32, i32),
}
fn main() {
    let q = Message::Quit;
    let m = Message::Move { x: 12, y: 24 };
    let w = Message::Write(String::from("Hello"));
    let c = Message::ChangeColor(0, 255, 255);
}

为枚举定义方法

使用impl关键字:

enum Message {
    Quit,
    Move { x: i32, y: i32 },
    Write(String),
    ChangeColor(i32, i32, i32),
}
impl Message {
    fn call(&self) {}
}
fn main() {
    let q = Message::Quit;
    let m = Message::Move { x: 12, y: 24 };
    let w = Message::Write(String::from("Hello"));
    let c = Message::ChangeColor(0, 255, 255);

    m.call();
}

Option枚举

  • 定义于标准库中
  • 在Prelude(预导入模块中)
  • 描述了:某个值可能存在(某种类型)或不存在的情况

Rust没有Null

其他语言中:

  • Null是一个值,它表示“没有值”
  • 一个变量可以处于两种状态:空值(null),非空

Null的问题在于:当你尝试像使用非Null值那样使用Null值的时候,就会引起某种错误

Null的概念还是有用的:因某种原因而变为无效或缺失的值

Rust中类似Null概念的枚举:Option\<T>

标准库中的定义:

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

它包含在Prelude(预导入模块中)。可以直接使用:

  • Option\<T>
  • Some(T)
  • None
let some_numebr = Some(5);
let some_string = Some("A String");

let absent_number: Option<i32> = None;

Option\<T>比Null好在哪里?

Option\<T>和T是不同的类型,不可以把Option\<T>直接当成T:

let some_numebr = Some(5);//Option<i32>
let some_string = Some("A String");//Option<&str>

let sum = x + y; //cannot add `Option<i8>` to `i8`

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

如果x与y中都不是Option\<T>,那它们就都不是Null。如果是Option\<T>,那么将需要先手动转换为T,从根本上避免了Null泛滥,这也体现了Rust的安全性。

控制流运算符:match

rust提供了一个强大的控制流运算符——match

  • 允许一个值与一系列模式进行匹配,并执行匹配的模式对应的代码
  • 模式可以是字面值、变量名、通配符等等。
enum Coin {
    Penny,
    Nickel,
    Dime,
    Quarter,
}

fn value_in_cents(coin: Coin) -> u8 {
    match coin {
        Coin::Penny => {
            println!("Penny!");
            1
        }
        Coin::Nickel => 5,
        Coin::Dime => 10,
        Coin::Quarter => 25,
    }
}

match运算符将coin与下面的值进行匹配,匹配相同时执行相应的语句,语句会返回表达式,这个表达式就是整个match这个表达式的值。因为上面的函数中match这个表达式作为返回值,所以上面的函数的返回值为匹配的模式对应的代码的返回值

模式对应多行代码的情况下,需要加上{}

绑定值的模式

匹配的分支可以绑定到被匹配对象的部分值。

  • 因此,可以从enum变体中提取值
#[derive(Debug)]
enum UsState {
    Alabama,
    Alaska,
}
enum Coin {
    Penny,
    Nickel,
    Dime,
    Quarter(UsState),
}

fn value_in_cents(coin: Coin) -> u8 {
    match coin {
        Coin::Penny => {
            println!("Penny!");
            1
        }
        Coin::Nickel => 5,
        Coin::Dime => 10,
        Coin::Quarter(state) => {
            println!("state quarter from {:?}!", state);
            25
        }
    }
}
fn main() {
    let c = Coin::Quarter(UsState::Alaska);
    println!("{}", value_in_cents(c));
    //  state quarter from Alaska!
    //  25
}

匹配Option\<T>

fn main() {
    let five = Some(5);
    let six = plus_one(five);
    let none = plus_one(None);
}

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

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

fn plus_one(x: Option<i32>) -> Option<i32> {
    match x {
        //non-exhaustive patterns: `None` not covered
        Some(i) => Some(i + 1),
    }
}

我们也可以使用_通配符来替代其余没列出的值:

let v = 0u8;//u8类型的0
match v {
    1 => println!("one"),
    2 => println!("two"),
    3 => println!("three"),
    4 => println!("four"),
    _ => println!("Aoligei!"),//_放在最后
}

if let

处理只关心一种匹配而忽略其他匹配的情况

下面两段代码效果相同:

fn main() {
    let v = Some(0u8);//u8类型的0
    match v {
        Some(3) => println!("three"),
        _ => (),
    }

    if let Some(3) = v {
        println!("three");
    }
}

if let的代码更简洁,但这也同时放弃了穷举的可能。

我们可以将if let看做match的语法糖

当然if let也可以搭配else使用,下面两段代码的效果相同:

fn main() {
    let v = Some(0u8);//u8类型的0
    match v {
        Some(3) => println!("three"),
        _ => println!("others"),
    }

    if let Some(3) = v {
        println!("three");
    } else {
        println!("others");
    }
}
相关文章
|
4月前
|
Rust 安全 网络协议
Rust 笔记:Rust 语言中的枚举 与 模式匹配
Rust 笔记:Rust 语言中的枚举 与 模式匹配
68 0
|
22天前
|
Rust 安全 C++
30天拿下Rust之枚举
Rust中的枚举是一种用户定义的类型,它允许你为一组相关的值赋予友好的名称。在Rust中,枚举是强大的工具,它们不仅仅用于表示几个固定的值,还可以包含函数和方法,使得枚举成员可以有自己的行为。通过与模式匹配和其他Rust特性结合使用,枚举在构建健壮、无崩溃的应用程序中发挥了重要作用,并可大幅提高代码的可读性、可维护性和类型安全性。
40 10
|
11天前
|
Rust 开发者 C#
解锁Rust高手的秘密武器:模式匹配与宏,学会这一招,编程效率翻倍!
【8月更文挑战第31天】Xamarin 是移动应用开发领域的强大跨平台工具,采用 C# 语言,具备高代码复用性、熟悉开发语言及接近原生性能等优势。开发者可通过共享项目实现多平台业务逻辑复用,简化开发流程。然而,Xamarin 也存在学习曲线陡峭、需处理平台差异及第三方库兼容性等问题。总体而言,Xamarin 在提高开发效率的同时,也对开发者提出了新的挑战。
14 0
|
3月前
|
Rust
Rust的if let语法:更简洁的模式匹配
Rust的if let语法:更简洁的模式匹配
|
4月前
|
Rust 安全 算法
【深入探索Rust:结构体、枚举与模式匹配】A Deep Dive into Rust: Structs, Enums, and Pattern Matching
【深入探索Rust:结构体、枚举与模式匹配】A Deep Dive into Rust: Structs, Enums, and Pattern Matching
76 0
【深入探索Rust:结构体、枚举与模式匹配】A Deep Dive into Rust: Structs, Enums, and Pattern Matching
|
4月前
|
Rust 安全
Rust语言中的控制流:条件语句、循环与模式匹配详解
本文将深入探讨Rust编程语言中的控制流构造,包括条件语句、循环和模式匹配。我们将了解如何使用这些工具来构建高效、可读和安全的代码。此外,我们还将探讨Rust在这些构造中提供的一些独特功能和优化。
|
4月前
|
C++ Rust NoSQL
Rust 数据类型 之 类C枚举 c-like enum
Rust 数据类型 之 类C枚举 c-like enum
52 0
Rust 数据类型 之 类C枚举 c-like enum
|
12天前
|
Rust 安全 Go
揭秘Rust语言:为何它能让你在编程江湖中,既安全驰骋又高效超车,颠覆你的编程世界观!
【8月更文挑战第31天】Rust 是一门新兴的系统级编程语言,以其卓越的安全性、高性能和强大的并发能力著称。它通过独特的所有权和借用检查机制解决了内存安全问题,使开发者既能享受 C/C++ 的性能,又能避免常见的内存错误。Rust 支持零成本抽象,确保高级抽象不牺牲性能,同时提供模块化和并发编程支持,适用于系统应用、嵌入式设备及网络服务等多种场景。从简单的 “Hello World” 程序到复杂的系统开发,Rust 正逐渐成为现代软件开发的热门选择。
29 1
|
24天前
|
Rust 安全 编译器
初探 Rust 语言与环境搭建
Rust 是一门始于2006年的系统编程语言,由Mozilla研究员Graydon Hoare发起,旨在确保内存安全而不牺牲性能。通过所有权、借用和生命周期机制,Rust避免了空指针和数据竞争等问题,简化了并发编程。相较于C/C++,Rust在编译时预防内存错误,提供类似C++的语法和更高的安全性。Rust适用于系统编程、WebAssembly、嵌入式系统和工具开发等领域。其生态系统包括Cargo包管理器和活跃社区。学习资源如&quot;The Book&quot;和&quot;Rust by Example&quot;帮助新手入门。安装Rust可通过Rustup进行,支持跨平台操作。
初探 Rust 语言与环境搭建
|
12天前
|
Rust 安全 程序员
Rust 语言的防错机制太惊人了!安全编码从此不再是难题,快来一探究竟!
【8月更文挑战第31天】《安全编码原则:Rust 语言中的防错机制》探讨了代码安全的重要性,并详细介绍了Rust语言如何通过内存安全模型、所有权与借用规则等特性,在编译阶段检测并阻止潜在错误,如缓冲区溢出和悬空指针。文章还讨论了类型安全、边界检查等其他安全特性,并提出了遵循不可变引用、避免裸指针及充分测试等实用编码原则,以进一步提升代码质量和安全性。随着Rust在软件开发中的应用日益广泛,掌握其安全编码原则变得尤为重要。
26 0