一起学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) } }
枚举类型就介绍到这里,要想快速掌握还是应该多多练习~
觉得还不错的话就关注下吧
完