《Rust 语言程序设计》笔记第五章-枚举和模式匹配

五、枚举和模式匹配

1、枚举

枚举定义
enum IpAddrKind {
    V4,
    V6,
}

创建实例:

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

函数签名的参数为枚举类型,那该枚举类型的成员都能传入:

fn route(ip_type: IpAddrKind) { }
route(IpAddrKind::V4);
route(IpAddrKind::V6);

枚举类型可以作为结构体的字段,同时,枚举成员也可以是其他类型(包括结构体)。

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

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

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

可以看到标准库也是类似的定义方式:

struct Ipv4Addr {
    // --snip--
}

struct Ipv6Addr {
    // --snip--
}

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

枚举类型同样可以通过 impl 定义方法

enum Message {
    Quit,
    Move { x: i32, y: i32 },
    Write(String),
    ChangeColor(i32, i32, i32),
}

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

let m = Message::Write(String::from("hello"));
m.call();
标准库 Option 枚举

Option 类型应用广泛因为它编码了一个非常普遍的场景,即一个值要么有值要么没值。

Rust 并没有空值,不过它确实拥有一个可以编码存在或不存在概念的枚举。这个枚举是 Option<T>,而且它定义于标准库中,如下:

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

Option 的成员不需要 Option:: 前缀就可以直接使用 。

let some_number = Some(5);
let some_string = Some("a string");

let absent_number: Option<i32> = None;

如果使用 None 而不是 Some,需要告诉 Rust Option<T> 是什么类型的,因为编译器只通过 None 值无法推断出 Some 成员保存的值的类型。

因为 Option<T>T(这里 T 可以是任何类型)是不同的类型,编译器不允许像一个肯定有效的值那样使用 Option<T>。例如,这段代码不能编译,因为它尝试将 Option<i8>i8 相加:

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

let sum = x + y;

在对 Option<T> 进行 T 的运算之前必须将其转换为 T

为了拥有一个可能为空的值,你必须要显式的将其放入对应类型的 Option<T> 中。接着,当使用这个值时,必须明确的处理值为空的情况。只要一个值不是 Option<T> 类型,你就 可以 安全的认定它的值不为空。

2、match 控制流运算

定义

match 是极为强大的控制流运算符,它允许我们将一个值与一系列的模式相比较,并根据相匹配的模式执行相应代码。

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,
    }
}
绑定值的模式

从枚举成员中提取值

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

enum Coin {
    Penny,
    Nickel,
    Dime,
    Quarter(UsState),
}

Coin 中有一种 25 美分硬币 Quarter 分别有50个州的不同版本,通过 match可以提取出州的值。

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

匹配Option<T>
fn main() {
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);
}
匹配是穷尽的
fn plus_one(x: Option<i32>) -> Option<i32> {
    match x {
        Some(i) => Some(i + 1),
    }
}

这段代码编译无法通过,因为没有考虑所有情况。

_通配符

Rust 也提供了一个模式用于不想列举出所有可能值的场景:

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

3、if let 简单控制流

只想匹配一种情况时,可以使用 if let

let some_u8_value = Some(0u8);
match some_u8_value {
    Some(3) => println!("three"),
    _ => (),
}
if let Some(3) = some_u8_value {
    println!("three");
}else {
    println!("others")
}

但是使用了 if let,就忽略了其他可能性,放弃了穷举。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值