Rust基礎(chǔ)學(xué)習(xí)-11-枚舉的使用

枚舉 enum,用于從眾多選項(xiàng)中選擇一個。

定義枚舉

#[derive(Debug)]
enum Week {
    Monday,
    Tuesday,
    Wednesday,
    Thursday,
    Friday,
    Saturday,
    Sunday,
}

fn main() {
    let today = Week::Saturday;  // 使用枚舉
    let tomorrow = Week::Sunday;

    println!("{:?}", today);
}

這是我們在很多面向?qū)ο笳Z言中常見的定義枚舉的方式

以往對枚舉的認(rèn)識,就是枚舉限定了幾個固定的選項(xiàng),我們只能使用眾多選項(xiàng)中的一個,或者說,只是使用了某一個元素的名字,例如上面Week枚舉中的Monday,至于Monday是什么,無所謂,Monday = 1也好,Monday = 10也好,我們并不關(guān)心。但是對于Rust,我們對枚舉有更進(jìn)一步的應(yīng)用。

用枚舉代替結(jié)構(gòu)體

#[derive(Debug)]
enum IpAddr {
    V4(u8, u8, u8, u8), // 這個枚舉成員是四個u8類型的元祖
    V6(String), // 這個枚舉成員是String類型
}

fn main() {
    // 定義一個枚舉變量,并將四個值存放
    let loopbackV4 = IpAddr::V4(127, 0, 0, 1);
  
    // 定義另一個枚舉變量,存入一個 String 類型的值
    // "xxx".to_string() 方法和 String::from("xxx") 是一樣的效果
    let loopbackV6 = IpAddr::V6("::1".to_string());

    println!("{:?}\n{:?}", loopbackV4, loopbackV6);
}

上面的代碼,我們可以給枚舉的每一個成員,指定一個數(shù)據(jù)類型,并且在創(chuàng)建一個枚舉變量的時候,將某個值存入枚舉。在 struct 中可以存儲不同類型的變量,現(xiàn)在,在枚舉中也可以。

再來看一個例子

// 定義一個操作枚舉
#[derive(Debug)]
enum Operation {
    Move {x: i32, y:i32},
    Jump(u32),
    Attack(i32),
}

fn main() {
    // 定義一個移動的操作
    let opt_move = Operation::Move {x: 10, y: 11};
  
    // 定義一個攻擊的操作
    let opt_attack = Operation::Attack(100);
  
    // 定義一個跳躍的操作
    let opt_jump = Operation::Jump(3);

    DoOperation(opt_move);
    DoOperation(opt_attack);
    DoOperation(opt_jump);
}

// 執(zhí)行操作
fn DoOperation(opt: Operation) {
    println!("Do operation: {:?}", opt);
}

上面的代碼我們定義了一個 Operation 枚舉,里面有移動,攻擊和跳躍三種操作方式。在 main 中定義了三個操作的變量,并且將每一次操作的具體值直接附加到了枚舉成員上,例如 opt_attack 攻擊操作,這次操作的傷害是100。

Rust 中使用 enum 代替 struct 將獲得更簡潔的代碼。并且,每個枚舉成員可以處理不同類型和數(shù)量的數(shù)據(jù)。

Rust 的 Option 枚舉解釋

Rust 中沒有 Null 值,無法將一個變量賦值為 Null, 例如 let a = Null;,這樣的操作在Rust中不存在。但是Rust中有 Option 枚舉,這個枚舉,用于表示 存在不存在 的概念。有點(diǎn)抽象,沒關(guān)系,一步一步來,先看下 Option 源代碼的定義

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

這里的 <T> 是指可以代表任何數(shù)據(jù)類型的,這是范型相關(guān)的東西,后面會學(xué)習(xí)??梢詫?Option 枚舉想象成可以裝不同類型東西的小盒子,例如我們定義了一個裝玩具汽車的小盒子,這個小盒子里只能裝玩具汽車。任何時候,只要這個盒子存在,那么里面就會有兩種狀態(tài),要么有玩具汽車,要么沒有玩具汽車。在有些面向?qū)ο蟮恼Z言中,如果訪問一個玩具汽車,而恰好當(dāng)時那里沒有玩具汽車,那么就會造成空引用,如果沒有手動處理空引用的情況,則程序就會出現(xiàn)Bug。而Rust則避免了 空引用 的情況。

看下面的代碼

fn main(){
  // 使用 Option 將一個 String 類型的值包起來
  let name: Option<String> = Some("Fred".to_string());
}

Option 用于某些地方可能存在有值或沒值的情況。Option 及成員已經(jīng)被自動包含,所以我們不需要 Option::Some(xxx) 這樣來使用。

match 匹配

對于 enum 類型的值,我們不能直接比較,看下面的代碼,是無法編譯通過的。

 let name: Option<String> = Option::Some("Jack".to_string());
println!(name == "Jack".to_string());

上面代碼中 name == "Jack".to_string() 編譯出錯,因?yàn)?== 兩邊的數(shù)據(jù)類型不一樣。這里,我們就可以用到 match。

看下面的代碼

#[derive(Debug)]
enum Operation {
    Move {x: i32, y:i32},
    Jump(u32),
    Attack(i32),
    Talk(String),
}

fn main() {
    let opt_talk = Operation::Talk("Hello".to_string());
    let opt_move = Operation::Move { x: 10, y: 20 };

    match opt_move {
        Operation::Talk(ref value) => { // 這里加了 ref 是為了避免所有權(quán)轉(zhuǎn)移
            println!("Talk: {:?}", value);
        },
        Operation::Move {x,y} => {
            println!("Move, x: {}, y: {}", x, y);
        }
        _ => {
            // nothing
        }
    }
}

上面的代碼中,match Operation 枚舉時,并沒有匹配所有的情況,所以最后需要 _ => ,相當(dāng)于某些編譯語言中 switch 中的 default,即在上面的情況都不匹配的情況下,執(zhí)行的操作。

if let 使用

直接看代碼,簡化上面 match 的操作

if let Operation::Move{x, y} = opt_move {
    println!("Move, x: {}, y: {}", x, y);
} else {
    println!("nothing");
}

這樣就可以不用 match 直接匹配枚舉中的某一個成員類型。

感覺這篇博客有些地方寫的可能不是很清楚,說明我對這塊知識的理解程度還不夠。下面是一些講解 Rust 枚舉的鏈接

https://rustwiki.org/zh-CN/rust-by-example/custom_types/enum.html

https://www.twle.cn/c/yufei/rust/rust-basic-enums.html

http://www.ameyalokare.com/rust/2017/10/23/rust-options.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容