Rust 枚举


枚举

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

定义枚举

枚举里面的字段被称为变体

enum IP{
 V4,
 V6, 
}

枚举值

let fout = IP::V4

将枚举传入函数

enum IP{
 V4,
 V6, 
}

fn main(){
  let four = IP::V4;

  route(four);
  route(IP::V6);
}

// 签名接收一个枚举
fn route(ipKind: IP){}

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

rust可以不通过结构体struct来为枚举赋值,可以直接赋值。

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

fn main(){
  let localhostV4 = IP::V4(127, 0, 0, 1);
  let localhostV6 = IP::V6(String::from("::1"));
}

可以在变体中嵌入任意类型的数据。

为枚举定义方法

使用 impl

impl SendMessage{
  fn call(&self){}
}

...
// 调用
let action = SendMessage::Quit;
action.call();
...

Option枚举

定义在标准库中,在Prelude(预导入模块)中。某个值(某种类型)可能存在或不存在的情况。

rust没有null,为了安全性。
但是rust有null的概念:因某种原因而变为无效或缺失的值。

enum Option { Some(T), None}

T是泛型枚举。

因为是预导入的枚举,所以可以直接使用这个枚举里的变体。

fn main(){
  let someNumber = Some(5);
  let someString = Some("hi");

  // 这个变量是没有有效的值,并且要主动声明是i32类型
  let unknow: Option = None;
}

Option 和 T 不是同一种类型。
eg: let x: i8 = 5; let y: Option = Some(5);

如果需要使用则需要转换,避免了一个问题:假设想使用这个值,但是这个值却为none。

match

允许一个值与一系列的模式进行匹配,并执行匹配的模式对应的代码。模式可以是字面值,变量名或通配符等。

有点类似python的反射,getattr,hasattr。或者其他语言的switch case。

enum Money {
    CNY,
    HKD,
    JPY,
    USD,
}

fn setMoney(money: Money) -> u8 {
    match money {
        Money::CNY => 500,
        Money::HKD => 1000,
        Money::JPY => 1500,
        Money::USD => {
            print!("change USD!");
            100
        },
    }
}

fn main() {}

match 会将传进来的参数与设置的变体依次比较,成功则返回。复杂的代码就多加个花括号。

匹配Option

match 里写 None,和Some(i)就行,i代表传入Some中的值。

match表达式必须穷举所有的表达式,就是匹配的枚举里的所有变体都要写进去。当变体比较多的时候可以使用 _ 通配符代替。

_ => ()
通配符要放在最后面。

match 中传参绑定

enum Money {
    CNY,
    HKD,
    JPY,
    USD(Bank),
}

#[derive(Debug)]
enum Bank {
    HSBC,
    BOC,
}

fn setMoney(money: Money) -> u16 {
    match money {
        Money::CNY => 500,
        Money::HKD => 1000,
        Money::JPY => 1500,
        Money::USD(Bank) => {
            print!("change USD in {:?}!", Bank);
            100
        },
    }
}

fn main() {
    let gotoUSA = Money::USD(Bank::BOC);
    setMoney(gotoUSA);
}

if let

简单的控制流,只关心一种匹配而忽略其他匹配。

if let 条件 = v {print!("{}", v)}

也可以搭配else

fn main() {
    let v = Some(2);
    if let Some(2) = v {
        print!("{:?}", v);
    } else {
        print!("others");
    }
}

总结

  1. Option 可能有值也可能为空,这样做是为了安全,想使用时就需要转换。反过来说,如果这个值不是option,那这个值一定不是为空的。类似强制做判断是否为空。