Rust 基础知识8 - 枚举相关知识

简介

  • 接上回

枚举的概念

  • 枚举允许我们列举所有可能的值来定义一个类型。
  • 使用关键字 enum 感觉和结构struct 很像:
#[derive(Debug)]
enum IpAddress {
    V4,
    V6
}
fn main() {
    // 初始化结构
    let a = IpAddress::V4;
    let b = IpAddress::V6;
    show_select(a);
    show_select(b);
}

// 这之后定义函数的时候,也可以限定传入枚举类型
fn show_select(sel:IpAddress) {
    println!("WOO:{:?}",sel);
}
image.png

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

  • 这个看起来会感觉更高级一些,改造一下上面的例子,让IpAddress 的枚举值具有某个类型,类似:
use std::io::Stdin;

#[derive(Debug)]
enum IpAddress {
    V4(String),
    V6(String),
}
#[derive(Debug)]
enum IpAddress2 {
    V4(u8,u8,u8,u8),
    V6(String),
}
fn main() {
    // 初始化结构
    let a = IpAddress::V4(String::from("127.0.0.1"));
    show_select(a);
    let b = IpAddress2::V4(192,168,1,1);
    show_select2(b);
}

// 这之后定义函数的时候,也可以限定传入枚举类型
fn show_select(sel:IpAddress) {
    println!("WOO:{:?}",sel);
}

// 这之后定义函数的时候,也可以限定传入枚举类型
fn show_select2(sel:IpAddress2) {
    println!("WOO:{:?}",sel);
}
image.png
  • 枚举也可以定义的比较花哨,例子:
#[derive(Debug)]
enum Message {
    Quit,
    Move {x:i32, y:i32},
    Write(String),
    ChangeColor(i32,i32,i32),
}
fn main() {
    // 初始化结构
    Message::Quit;
    Message::Move {x:100, y:200};
    Message::Write(String::from("Hello."));
    Message::ChangeColor(255,255,0);
}

给枚举定义方法

  • 枚举也可以向结构一样定义方法,同样通过 impl 关键字
  • 举个栗子:
#[derive(Debug)]
enum Message {
    Quit,
    Move {x:i32, y:i32},
    Write(String),
    ChangeColor(i32,i32,i32),
}

impl Message {
    fn show (&self) {
        println!("{:?}", &self ) ;
    }
}

fn main() {
    // 初始化结构
    let a = Message::ChangeColor(255,255,0);
    a.show();

    let a = Message::Write(String::from("I known."));
    a.show();
}

image.png

Rust 没有 Null ,通过枚举来解决

  • 这是Rust 的有点之一,面向对象设计原则中有一条就是要尽量避免使用null值,恰巧Rust 从语言特性上直接拒null值了,
// 标准库中的定义,包含在Prelude(预导入模块)中。可以直接使用:
enum Option {
    Some(T),
    None,
}

Option 比Null 好在哪儿?

  • Option 和 T 是不同的类型,不可以吧Option直接当成T使用,如果想使用Option中的T必须将其转换成T,不好理解的话看下面的代码就可以了。


    image.png
  • 会导致编译报错:上面 var1 推导类型是 Option var2 推导类型是 i32 ,这两种类型不能直接相加。


    image.png
  • 那么要向相加需要怎么办呢,请看:
fn main(){
    let var1 = Some(5);
    // let var1 = None; // 如果这样那么编译的时候就会报错,这样也就更安全
    let var2 = 6;
    if let Some(x) = var1 {
        println!("Sum val is : {}" , x + var2);
    }else{
        println!("var1 can not equal None")
    }
}
  • 把上面的例子,改进了一下换个角度在理解一下:
fn main(){
    let var1 = Some(5);
    // let var1 = None; // 如果这样那么编译的时候就会报错,这样也就更安全
    let var2 = Some(6);
    let result = sum(var1, var2);
    dbg!(result);
    
}

// 定义一个函数
fn sum(x:Option, y:Option) -> Option {
    match x {
        Some(x) =>{
            match y {
                Some(y) => {
                    Some(x + y)
                },
                None => {
                    None
                },
            }
        },
        None => {
            None
        },
    }
}

  • 再看看这个举例,就应该明白了,注意看代码中的注释:

fn main(){
    let x = area_counter(10, 30);
    show_info(x);
    let x = area_counter(-10, 30);
    show_info(x);
    
}
// 统一返回枚举 Option,只是其中变体不同,这样便于后续判断,也防止遗忘
fn area_counter(x:i32, y:i32) ->Option{
    if x < 0 || y < 0 {
        None
    }else{
        Some(x * y)
    }
}

// 打印变量信息,接收参数Option 也就代表接收Option::None 变体,所以相应变体值也要处理
fn show_info(var:Option) {
    // 如果不是Some 值那么就是None值了,他们都是Option 枚举的不同变体
    if let Some(trueval) = var {
        println!("B value is : {}", trueval);
    } else {
        // 不是Some变体肯定就是 None 变体了。
        println!("Null value");
    }
}

枚举enum和struct最大的差别

  • 枚举更像是struct 的一个集合体。
  • 枚举的定义更像是某个对象的不同状态的表达,也就是说可以给某个类型定义多种变体。
  • 类似这种情况都应该用Option 作为返回值。

结束

  • 感谢阅读。

你可能感兴趣的:(Rust 基础知识8 - 枚举相关知识)