­

一起学Rust-枚举

  • 2019 年 10 月 6 日
  • 筆記

一、枚举定义及使用

枚举的定义在其他许多的语言中都有实现,举例来说,比如C中的枚举,枚举值在未赋值的情况下默认从0开始递增或从上一个枚举值开始递增,值类型可以是整数或字符类型,实质只能保存整型:

enum {      A = 'd',  //d 的 ascii码值      B,        //e 的 ascii码值      C,        //f 的 ascii码值      D = 10,      E,        //11  };

Rust中的枚举与C中的枚举不同,功能非常强大,可以用枚举表达更多的可能性数据。

看一下基本的枚举定义:

//定了一个性别的枚举  enum Gender {      Male,      Female,  }

这里面不同的是,Male和Female不是变量,而是枚举值,而不像是C中会访问到相应的数字。

#[derive(Debug)]  enum Gender {      Male,      Female,  }    println!("{:?}, {:?}", Gender::Male, Gender::Female);    ----- 输出 -----  Male, Female

虽然输出看上去是字符串类型,但实际是枚举Gender类型

//这样是编译不通过的  if Gender::Male == "Male" {...}

枚举值的代数形式是可以与实际的值进行结合的,而且是可以结合不同类型的数据,这使得枚举的能力更强:

enum ErrorLevel {      Error(String),      Info(String, i32),      Warning(String),  }

每一个枚举值可可以放入不同类型的数据,作为枚举的一部分,那么通过下面的例子看一下如何定义带数据的枚举值:

let info = ErrorLevel::Info("info error".to_string(), 3);    match info {      ErrorLevel::Info(k, v)  => {          println!("{}, {}", k, v);      },      _ => ()  }

上面的例子里面通过模式匹配获取了Info枚举值内的数据,这里需要注意的是上面的例子在match代码块后方就不能再使用info的变量了,这里涉及到Rust中所有权的特性,也是Rust中非常重要的特性,这里暂不过多的探讨。

不过上面的例子仅支持固定类型的值,对于不同级别的错误日志来说,有些时候会需要记录一些不同类型的数据,所以可能需要不同的参数类型(这样说稍微牵强),看下面枚举结合 泛型 的例子:

enum ErrorLevel<T> {      Error(T),      Info(T),      Warning(T),  }  let info = ErrorLevel::Info("abc");  //可以通过自动推断类型  let info = ErrorLevel::<&str>::Info("abc");  //可以指定类型并赋值

三、内置常用枚举

Option<T> 枚举类型,通过IDE可以查看它的完整定义:

#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)]  #[stable(feature = "rust1", since = "1.0.0")]  pub enum Option<T> {      /// No value      #[stable(feature = "rust1", since = "1.0.0")]      None,      /// Some value `T`      #[stable(feature = "rust1", since = "1.0.0")]      Some(#[stable(feature = "rust1", since = "1.0.0")] T),  }

简化如下

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

Option<T> 是一个非常重要的枚举类型,在程序中无需引用库,直接可以使用Some(T)和None。另外一个原因是因为Rust中去除了空类型,也就是没有null、nil、none、这种在其他语言中非常常见的空类型,而是使用 Option<T> 作为存在值和空值间的选择,因为 Option<T> 可以被赋予指定类型,即使当变量还为初始化时,也是明确变量应该被设置的类型。

let num:Option<i32> = None;  //当变量暂不可知时,赋予None

上面的例子中,赋值为None时必须明确Option的类型,通过None是无法推断Option中值的类型的。

在上一期的《一起学Rust-实战leetcode(一)》中使用到的HashMap,其get方法获取到的就是一个Option<T>枚举类型,存在则返回Some包含的值,哈希中不存在则返回None。

Result<T,E> 枚举类型,仅有两个枚举值:

enum Result<T, E> {      Ok(T),    //成功情况      Err(E)    //失败情况  }

在这个枚举用的比较广泛,例如 Tcp连接的创建、文件读取、标准输入等,会存在成功或异常的情况,所以通过枚举类型携带成功或错误的信息返回。

fn main() {      let mut input  = String::new();    //    if let Ok(string_bytes) = stdin().read_line(&mut input) {  //        println!("{}, {}", string_bytes, input);  //    } else {  //        println!("error");  //    }        //这里写法上方的写法意义是一样的,      let res = stdin().read_line(&mut input);      match res {          Ok(v) => println!("{}, {}", v,  input),          Err(e) => println!("{}", e)      }  }

枚举类型就介绍到这里,要想快速掌握还是应该多多练习~

觉得还不错的话就关注下吧