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)

将Option<T>转换为Option<&T>,使用后b类型将从: String 变为: &String。已稳定
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

如果Some有值就返回Some,否则停止运行。该方法在Rust中不稳定,随时可能被去除。推荐调用 unwrap_or,unwrap_or_else 或者 unwrap_or_default
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

如果存在返回Some数值,如果不存在返回默认值。该方法在Rust中不稳定,随时可能被去除。
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

如果Some有值就不执行unwrap_or_else中的语句而是返回Some,如果是None就执行并返回结果。该方法在Rust中不稳定,随时可能被去除。
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

如果Some有值就返回Some,否则返回None 类型的默认值,比如i8,u8返回0 string,str返回””
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