(四)Rust_枚举与模式匹配


枚举与模式匹配

枚举

  1. 枚举允许列举所有可能的值来定义一个类型。与 Cpp 类似。

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

    • 不再需要额外使用 struct。
    • 每个变体可以拥有不同的类型以及关联的数据量。
    enum IpAddr{
        V4(String),
        V6(String),
    }
    
    enum IpAddr{
       V4(u8, u8, u8, u8),
       V6(String),
    }
    

为枚举定义方法

  1. 可以使用 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 枚举

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

Rust 没有 Null

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

    • 但是 Null 概念为了表示因某种原因而变为无效或缺失的值还是必须的,因此 Rust 提供了 Option。
  2. Rust 中类似 Null 概念的枚举- Option<T>

    • 它包含在预导入模块中,可以直接使用。
     enum Option<T>{
         some(T),
         None,
     }
    
     let some_number = Some(5);
     let some_string = Some("A String");
    
     let absent_number: Option<i32> = None; // None 类型不会自动推导需要指定
    
  3. 这样设计的优势在于 Option<T> 和 T 是不同的类型,不可以把 Option<T> 直接当成 T 来使用。

    • 若想使用 Option<T> 中的 T,必须将它转换为 T。
     let x: i8 = 5;
     let y: Option<i8> = Some(5);
     let sum = x + y; // error,必须强转后才能使用
    

控制流运算符 - match

  1. match 允许一个值与一系列模式进行匹配,并执行匹配的模式对应代码。

  2. 模式可以是字面值、变量名、通配符等。

    enum Coin {
        Penny,
        Nickel,
        Dime,
        Quarter,
    }
    
    fn test_match(coin: Coin) -> u8 {
        match coin {
            Coin::Penny => {
                println!("Penny");
                1
            }
            Coin::Nickel => 5,
            Coin::Dime => 10,
            Coin::Quarter => 25,
        }
    }
    
  3. 绑定值的模式,匹配的分支可以绑定到被匹配对象的部分值。

    • 因此,可以从 enum 变体中提取值。
     #[derive(Debug)]
     enum UsState {
         Alabama,
         Alaska,
     }
    
     enum Coin {
         Penny,
         Nickel,
         Dime,
         Quarter(UsState),
     }
    
     fn test_match(coin: Coin) -> u8 {
         match coin {
             Coin::Penny => {
                 println!("Penny");
                 1
             }
             Coin::Nickel => 5,
             Coin::Dime => 10,
             Coin::Quarter(state) => { // 绑定 state 值进行模式匹配
                 println!("State quarter from {:?}!", state);
                 25
             }
         }
     }
    
  4. 模式匹配 Option<T>

     fn call() {
         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),
         }
     }
    
  5. match 匹配必须穷举所有的可能,不关心的分支可以用 _ 通配符。

     let v = 0_u8;
     match v {
         1 => println!("one"),
         3 => println!("three"),
         _ => (),
     }
    

if let

  1. 处理只关心一种匹配而忽略其他分支的情况。

    • 更少的代码,更少的缩进,更少的模版代码。
    • 放弃了穷举的可能。
     let v = Some(0_u8);
     match v {
         Some(3) => println!("three"),
         _ => (),
     }
    
     if let Some(3) = v {
         println!("three");
     }
    
  2. 搭配 else 进行使用。

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

文章作者: Layton
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Layton !
  目录