11、初识Rust – 枚举与模式匹配
上一篇文章学习了结构体,结构体支持多种数据类型配合 impl 有非常不俗的灵活性。但是结构体可以绑定的数据类型依然有限。当我们需要更好的灵活性时,枚举就是一个非常不错的解决方法 。
枚举使用关键字 enum 声明。假设我们要处理IP地址,目前被广泛使用的两个主要IP标准是 ipv4和ipv6。如果我们程序需要处理IP地址,那么它就会遇到两种类型的地址中的一种,所以需要枚举出所有可能的值,这也是枚举名字的由来。
enum IpAddrKind { v4, v6, }
如上我们声明一个枚举,并创建2个枚举 成员,v4和v6。
现在开始,IpAddrKind就是一个可以在代码中使用的自定义数据类型了。
enum IpAddr { V4(String), V6(String), } fn main() { let ipv4 = IpAddr::V4(String::from("127.0.0.1")); let ipv6 = IpAddr::V6(String::from("::1")); }
如上是一个非常简单的,为枚举中赋予值的方式,从中我们可以发现 IpAddr::V4()其实是一个获取参数并返回IpAddr类实例的函数调用。目前我们还没有遇到与结构体不一样的地方,接下来将展示枚举的特色。
enum IpAddr { V4(u8,u8,u8,u8), V6(String), } fn main() { let ipv4 = IpAddr::V4(127,0,0,1); let ipv6 = IpAddr::V6(String::from("::1")); }
如上,枚举与结构体不同的地方在于,枚举可以在其中放入任意类型的数据,比如字符串,数字,结构体,元组,甚至包含另一个枚举。
enum Test { Rgb(i32,i32,i32), Xyz {x: i32, y: i32, z: i32}, Value(String), }
如上的枚举,它包含了3种不同类型的成员。
- Rgb 包含3个 i32
- Xyz包含一个类似结构体的字段
- Value 包含一个字符串
枚举像结构体一样,也可以使用 impl 来为结构体定义方法。
enum Test { Rgb(i8,i8,i8), Xyz {x: i32, y: i32, z: i32}, Value(String), } impl Test { fn call(&self){ //处理 } } fn main() { let a = Test::Rgb(1,2,3); let b = a.call(); }
在标准库中存在另一个枚举 Option。 Option类型应用广泛,因为它编码了一个非常普遍的场景,那就是一个值要么有值要么没值。比如请求一个包含项的列表的第一个值,如果请求了一个空列表,那就什么都不会得到,如果不做特殊处理,那么程序运行时可能会出现错误。
由于Rust没有大多数语言中的空值功能(Null)但是它有一个可以编码存在或者不存在概念的枚举。这个枚举就是 Option<T>
enum Option<T> { None, Some(T), }
Option的成员不需要使用Option::前缀来直接使用Some和None,但是Option<T>依旧是一个常规的枚举,Some(T)和None依旧是它的成员。
<T>语法是一个泛型类型的参数,目前我们了解的<T> 意味着Option 枚举的Some成员可以包含任意类型的数据,同时每一个用于 T 位置的具体类型使用 Option<T> 整体作为不同的类型。
Option<T>带有非常多的方法,对Option<T>的使用和了解非常的有用。
is_some(&self) -> bool
is_some方法,如果Option中的Some中存在值,则返回true,否则返回false。该方法在Rust中已稳定。
fn main(){ let a = Some(1); println!("{}",a.is_some()); //true }
is_none(&self) -> bool
is_none方法,如果值为None,则返回true,否则false。已稳定
fn main(){ let a = None; println!("{}",a.is_none()); }
as_ref(&self) -> Option(&T)
fn main(){ let a: Option<String> = Some(String::from("abc")); let b: Option<&String> = a.as_ref(); }
as_ref(&mut self) -> Option<&mut T>
将Option<&T>转为Option<&mut T>该方法在Rust中不稳定,随时可能被去除。
fn main() { let mut a: Option<String> = Some(String::from("abc")); let b: Option<&mut String> = a.as_mut(); println!("{:?}",b) }
expect(self, msg: &str) -> T
从Option<T>中返回值T,如果值是None,则会引起线程恐慌,并显示自定义紧急消息msg,该方法在Rust中不稳定,随时可能被去除。
fn main(){ let b:Option<i8> = None; let c = b.expect("值是None"); } ------------------------------------------------------------------- Compiling master v0.1.0 (/Users/xxxx) Finished dev [unoptimized + debuginfo] target(s) in 0.54s Running `target/debug/master` thread 'main' panicked at '值是None', src/main.rs:4:7 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace ################################################################### fn main(){ let b:Option<i8> = Some(2); let c = b.expect("值是None"); println!("{}",c); } -------------------------------------------------------------------- Compiling master v0.1.0 (/Users/xxx) Finished dev [unoptimized + debuginfo] target(s) in 0.54s Running `target/debug/master` 2
unwrap(self) -> T
fn main() { let b:Option<i8> = None; b.unwrap(); } ----------------------------------------------------------------------------- Compiling master v0.1.0 (/Users/xxxx) Finished dev [unoptimized + debuginfo] target(s) in 0.52s Running `target/debug/master` thread 'main' panicked at 'called `Option::unwrap()` on a `None` value', src/main.rs:4:7 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace ############################################################################# fn main() { let b = Some(1); let a = b.unwrap(); println!("{}",a); } ----------------------------------------------------------------------------- Compiling master v0.1.0 (/Users/xxxx) Finished dev [unoptimized + debuginfo] target(s) in 0.52s Running `target/debug/master` 1
unwrap_or(self, default: T) -> T
fn main() { let b: Option<i8> = None; let c = b.unwrap_or(1); println!("{}",c); } ------------------------------------------------------------- Finished dev [unoptimized + debuginfo] target(s) in 0.04s Running `target/debug/master` 1 ############################################################# fn main() { let b: Option<i8> = Some(2); let c = b.unwrap_or(1); println!("{}",c); } ------------------------------------------------------------- Finished dev [unoptimized + debuginfo] target(s) in 0.04s Running `target/debug/master` 2
unwrap_or_else<F> (self, f: F) -> T
fn main() { let b = Some(2).unwrap_or_else(|| 2 * 2); let c = None.unwrap_or_else(|| 2 * 2); println!("{},{}",b,c); } ----------------------------------------------------------------- Compiling master v0.1.0 (/Users/xxxxxx) Finished dev [unoptimized + debuginfo] target(s) in 0.62s Running `target/debug/master` 2,4
unwrap_or_default (self) -> T
fn main() { let a:Option<f32> = None; let b = Some(2); let c = a.unwrap_or_default(); let d = b.unwrap_or_default(); println!("{},{}",c,d); } --------------------------------------------------------------------- Compiling master v0.1.0 (/Users/xxxxxxx) Finished dev [unoptimized + debuginfo] target(s) in 0.57s Running `target/debug/master` 0,2