Rust(六)-枚举与模式匹配

114 阅读3分钟

定义玫举

  • 枚举
    • 枚举允许我们列举所有可能的值来定义一个类型
  • 定义枚举
    • ip地址:ipv4,ipv6
    •   enum IpAddrKind {
          V4,
          V6,
      }
      
      fn main() {
          let four = IpAddrKind::V4;
          let six = IpAddrKind::V6;
      
          route(IpAddrKind::V4);
          route(IpAddrKind::V6);
      }
      
      fn route(ip_kind: IpAddrKind) {}
      
      
  • 枚举值:
    •       enum IpAddrKind {
              V4,
              V6,
          }
      
          fn main() {
              let four = IpAddrKind::V4;
              let six = IpAddrKind::V6;
      
              route(IpAddrKind::V4);
              route(IpAddrKind::V6);
          }
      
          fn route(ip_kind: IpAddrKind) {}
      
      
  • 将数据附加到枚举的变体中
    •       fn main() {
             enum IpAddrKind {
                 V4,
                 V6,
             }
      
             struct IpAddr {
                 kind: IpAddrKind, 
                 address: String,
             }
      
             let home = IpAddr {
                 kind: IpAddrKind::V4,
                 address: String::from("127.0.0.1"),
             };
      
             let loopback = IpAddr {
                 kind: IpAddrKind::V6,
                 address: String::from("::1"),
             };
         }
      
      
    • 优点
      • 不需要额外的使用struct
      • 每个变体可以拥有不同的类型以及关联的数据量
     fn main() {
            enum IpAddr {
                V4(u8, u8, u8, u8),
                V6(String),
            }
    
            let home = IpAddr::V4(127, 0, 0, 1);
    
            let loopback = IpAddr::V6(String::from("::1"));
        }
    
    • 标准库中的ipaddr +
      
       #![allow(unused)]
       fn main() {
       struct Ipv4Addr {
           // --snip--
       }
      
       struct Ipv6Addr {
           // --snip--
       }
      
       enum IpAddr {
           V4(Ipv4Addr),
           V6(Ipv6Addr),
       }
       }
      
      
  • 为玫举定义方法
fn main() {
   enum Message {
       Quit,
       Move { x: i32, y: i32 },
       Write(String),
       ChangeColor(i32, i32, i32),
   }

   impl Message {
       fn call(&self) {
           // method body would be defined here
       }
   }

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

枚举与模式匹配

  • option枚举
    • 定义于标准库中
    • 在prelude(预导入模块)中
    • 描述了: 某个值可能存在(某种类型)或不存在的情况
  • Rust 没有 null
    • 其它语言中:
      • Null是一个值,它表示“没有值”
      • 一个变量可以处于两种状态:空值(null)、非空
    • Null 引用:Billion Dolloar Mistake
    • Null的问题在于:当你尝试像使用非Null值那样使用的Null值的时候,就会引起某种错误
    • Null的概念还是有用的:困某种原因而变为无效或缺失的值
  • Rust中类似Null概念的枚举 - Option T
    • 标准库中的定义:
      #![allow(unused)]
      fn main() {
          enum Option<T> {
              None,
              Some(T),
          }
      }
    
    • 它包含在prelude(预导入模块)中。可直接使用
    Option<T>
    Some(T)
    None
    
  • Option< T > 比 null 好在哪?
    • Option< T > 和 T 是不同的类型,不可以把Option< T > 当成T
    • 若想使用Option< T >中T,必须使用它转换成T
    • 而在C#中:
      • string a = null
      • string b = a + '12345'

近制流运算符-match

  • 强大的控制流运算符-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() {}
    
    
  • 绑定值的模式
    • 匹配的分支可以绑定到被匹配对象的部分值
      • 因此, 可以从enum变体中提取值
    #[derive(Debug)] // so we can inspect the state in a minute
      enum UsState {
          Alabama,
          Alaska,
          // --snip--
      }
    
      enum Coin {
          Penny,
          Nickel,
          Dime,
          Quarter(UsState),
      }
    
      fn main() {}
      #[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));
      }
    
    
  • 匹配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);
      }
    
  • match 匹配必须穷举所有的可能
    • _通配符: 替人其余没列出的值

if let

  • 处理只关心一种匹配而忽略其它匹配的情况
  • 更少的代码,更少的缩进,更少的模板代码
fn main() {
    let config_max = Some(3u8);
    match config_max {
        Some(max) => println!("The maximum is configured to be {}", max),
        _ => (),
    }
}