rust 学习记录 VI 枚举和模式匹配

枚举和模式匹配

定义枚举

定义

枚举就是用来列出所有的值。

enum ipAddrKind {
    V4,
    V6,
}

fn main() {
    let four = ipAddrKind::V4;
    let six = ipAddrKind::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"),
    };
}

进一步优化我们可以将这个结构体省略掉,rust 允许我们将类型作为参数传递给枚举,所以我们这里就不需要将枚举再次作为一个结构体的字段了。

#![allow(unused)]
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"));
}

使用枚举还有一个好处,那就是枚举可以非常轻易地处理多个不同类型的参数:

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

fn main() {
    let home = ipAddrKind::V4(127, 0, 0, 1);
}

枚举相对于结构体的一个好处

当我们需要一个统一个方法来处理不同的结构体的时候,我们这时候使用枚举会比较方便。

看官方的例子:

// 这是一个枚举
enum Message {
    Quit,
    Move { x: i32, y: i32 },
    Write(String),
    ChangeColor(i32, i32, i32),
}

// 这是对应的结构体
struct QuitMessage; // 类单元结构体
struct MoveMessage {
    x: i32,
    y: i32,
}
struct WriteMessage(String); // 元组结构体
struct ChangeColorMessage(i32, i32, i32); // 元组结构体

如果我们要处理这结构体类型很明显我们需要定义四个方法,但是如果对于枚举来说,因为枚举本身是一个类型,所以我们只需要定义一个方法即可。

像下面这样:

impl Message {
    fn call(&self) {
        // 在这里定义方法体
    }
}

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

option 枚举

option 是一个特别常见的枚举,以至于已经被内置到了 preclude 中了,我们甚至可以不需要引入就可以使用。

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

我们来看一个例子,比如有一个数字我们不确定它是否存在我们就可以这样定义:

fn main() {
    let x = Some(5);
    let y = 10;
    let z = x + y;
}

这时候如果我们直接计算 z,即直接将一个类型为 Option(i32) 的值和类型为 i32 的值相加,rust 的编译器就会报错,因为 Option(i32) 类型的值可能为 None,所以我们在相加之前,就需要判断这个值是否为 None,可以像下面这样处理:

fn main() {
    let x = Some(5);
    let y = 10;
    match x {
        Some(value) => {
            let z = value + y;
			println!("z = {}", z)
        }
        None => {
            println!("do nothing")
        }
    }
}

match 控制流运算符

match 和枚举一起使用

Rust 有一个叫做 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,
    }
}

fn main() {
    let x = value_in_cents(Coin::Penny);
    println!("x = {}", x);
}

下面的这个例子也是一样的道理,只不过嵌套了一个枚举:

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

match 和 Option<T>类型一起使用

我们还是看上面的例子,我们这里就是用 match 处理了为 None 的情况。

fn main() {
    let x = Some(5);
    let y = 10;
    match x {
        Some(value) => {
            let z = value + y;
			println!("z = {}", z)
        }
        None => {
            println!("do nothing")
        }
    }
}

此外,还有一点,match 是穷尽的,也就是说如果我们只匹配了一部分,神奇的 rust 编译器就会报错。

other 和 _ 占位符

  • other 表示处理没有匹配到的剩余的情况,可以获取匹配到的值
  • _ 表示匹配所有的情况,一般就放在最下面,无法获取匹配到的值

比如还是刚刚的例子,我们可以使用 other 处理一些情况:

#[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,
        // other
        other => 0,
    }
}

fn main() {
    let x = value_in_cents(Coin::Quarter(UsState::Alaska));
    println!("x: {}", x);
}

if let 简单控制流

if let 我们用来处理只有一个分支需要处理的情况,其他的情况我们使用 else。

fn main() {
    let x = Some(3);

    // 1
    match x {
        Some(3) => println!("three"),
        _ => println!("anything"),
    }

    // 2
    if let Some(3) = x {
        println!("three");
    } else {
        println!("other");
    }
}

这个还是比较好理解的。

  • 10
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

城南顾北

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值