目錄
1、枚舉的定義
1.1?Option 枚舉和其相對于空值的優(yōu)勢
?2、match 控制流結(jié)構(gòu)
2.1?匹配 Option
2.2?匹配是窮盡的
2.3?通配模式和 _ 占位符
3、if let 簡潔控制流
1、枚舉的定義
枚舉(enumerations),也被稱作?enums。枚舉允許你通過列舉可能的?成員(variants)來定義一個類型。首先,我們會定義并使用一個枚舉來展示它是如何連同數(shù)據(jù)一起編碼信息的。接下來,我們會探索一個特別有用的枚舉,叫做?Option
,它代表一個值要么是某個值要么什么都不是。然后會講到在?match
?表達(dá)式中用模式匹配,針對不同的枚舉值編寫相應(yīng)要執(zhí)行的代碼。最后會介紹?if let
,另一個簡潔方便處理代碼中枚舉的結(jié)構(gòu)。
下面看下下面這個示例:
#[derive(Debug)]
enum Sex {
Man,
Woman,
}
fn main() {
let var = Sex::Man;
println!("value is {:?}", var)
}
從上面代碼示例中,我們把性別可以枚舉出來,引用枚舉類型的某一個值的時候,可以通過枚舉名后面加一堆冒號來引用枚舉中的某一個屬性值。
下面這個例子,我們可以在枚舉中,它的成員可以有多種類型:
enum op {
name(String),
time(i32),
People { name: String, age: i32 },
}
有關(guān)聯(lián)值的枚舉的方式和定義多個不同類型的結(jié)構(gòu)體的方式很相像,除了枚舉不使用?struct
?關(guān)鍵字以及其所有成員都被組合在一起。
結(jié)構(gòu)體和枚舉還有另一個相似點:就像可以使用?
impl
?來為結(jié)構(gòu)體定義方法那樣,也可以在枚舉上定義方法。
enum Op {
Name(String),
Time(i32),
People { name: String, age: i32 },
}
impl Op {
fn say(&self) {}
}
讓我們看看標(biāo)準(zhǔn)庫中的另一個非常常見且實用的枚舉:Option
。
1.1?Option 枚舉和其相對于空值的優(yōu)勢
這一部分會分析一個?Option
?的案例,Option
?是標(biāo)準(zhǔn)庫定義的另一個枚舉。Option
?類型應(yīng)用廣泛因為它編碼了一個非常普遍的場景,即一個值要么有值要么沒值。
例如,如果請求一個非空列表的第一項,會得到一個值,如果請求一個空的列表,就什么也不會得到。從類型系統(tǒng)的角度來表達(dá)這個概念就意味著編譯器需要檢查是否處理了所有應(yīng)該處理的情況,這樣就可以避免在其他編程語言中非常常見的 bug。
編程語言的設(shè)計經(jīng)常要考慮包含哪些功能,但考慮排除哪些功能也很重要。Rust 并沒有很多其他語言中有的空值功能。空值(Null?)是一個值,它代表沒有值。在有空值的語言中,變量總是這兩種狀態(tài)之一:空值和非空值。
然而,空值嘗試表達(dá)的概念仍然是有意義的:空值是一個因為某種原因目前無效或缺失的值。
問題不在于概念而在于具體的實現(xiàn)。為此,Rust 并沒有空值,不過它確實擁有一個可以編碼存在或不存在概念的枚舉。這個枚舉是?Option<T>
,而且它定義于標(biāo)準(zhǔn)庫中,如下:
fn main() {
enum Option<T> {
None,
Some(T),
}
}
Option<T>
?也仍是常規(guī)的枚舉,Some(T)
?和?None
?仍是?Option<T>
?的成員。<T>
?語法是一個我們還未講到的 Rust 功能。它是一個泛型類型參數(shù),所以你需要知道的就是?<T>
?意味著?Option
?枚舉的?Some
?成員可以包含任意類型的數(shù)據(jù),同時每一個用于?T
?位置的具體類型使得?Option<T>
?整體作為不同的類型。這里是一些包含數(shù)字類型和字符串類型?Option
?值的例子:
enum Option<T> {
None,
Some(T),
}
let some_number = Some(5000);
let some_char = Some('e');
let some_boolean = Some(true);
讓我們再看一下如下示例,定義如下2個值進(jìn)行相加會怎么樣?
fn main() {
enum Option<T> {
None,
Some(T),
}
let some_number: i8 = 5;
let absent_number: Option<i8> = Some(5);
let plus = some_number + absent_number;
}
運行結(jié)果如下所示:
在這里有2個嚴(yán)重的問題:
第一個問題是let absent_number: Option<i8> = Some(5); 在這里賦值的時候會報錯,這2個類型名看起來很像,但實際上是不同的類型,無法進(jìn)行賦值操作。
第二個是不同類型進(jìn)行相加的時候,當(dāng)在 Rust 中擁有一個像?i8
?這樣類型的值時,編譯器確保它總是有一個有效的值。我們可以自信使用而無需做空值檢查。只有當(dāng)使用?Option<i8>
(或者任何用到的類型)的時候需要擔(dān)心可能沒有值,而編譯器會確保我們在使用值之前處理了為空的情況。
?2、match 控制流結(jié)構(gòu)
Rust 有一個叫做?match
?的極為強大的控制流運算符,它允許我們將一個值與一系列的模式相比較,并根據(jù)相匹配的模式執(zhí)行相應(yīng)代碼。模式可由字面值、變量、通配符和許多其他內(nèi)容構(gòu)成;
我們看一下如下示例,能夠更清楚的明白match的作用:
fn main() {
enum Coin {
Penny,
Nickel,
Dime,
Quarter,
}
fn value_in_cents(coin: Coin) -> u8 {
match coin {
Coin::Penny => 1,
Coin::Nickel => 5,
Coin::Dime => 10,
Coin::Quarter => 25,
}
}
let res = value_in_cents(Coin::Nickel);
print!("result {}", res) // result 5
}
match 的作用,其他跟其他語言(例如,JavaScript)中的switch差不多,以上代碼中,方法接收了一個枚舉類型,match根據(jù)枚舉類型的不同成員來返回的不同的值,類似不同的分支,符合條件的分支,才會被最后返回,如果匹配到了某一個分支,想在執(zhí)行其他邏輯的時候,可以加一對花括號,在里面寫對應(yīng)的邏輯即可。
fn value_in_cents(coin: Coin) -> u8 {
match coin {
Coin::Penny => {
print!("res: 執(zhí)行到這了");
1
}
Coin::Nickel => 5,
Coin::Dime => 10,
Coin::Quarter => 25,
}
}
2.1?匹配 Option<T>
下面編寫一個函數(shù),它獲取一個?Option<i32>
?,如果其中含有一個值,將其加一。如果其中沒有值,函數(shù)應(yīng)該返回?None
?值。
fn plus_one(x: Option<i32>) -> Option<i32> {
match x {
None => None,
Some(i) => Some(i + 1),
}
}
let five = Some(5);
let six = plus_one(five);
let none = plus_one(None);
println!("{:?} {:?} {:?}", five, six, none) // Some(5) Some(6) None
2.2?匹配是窮盡的
match
?還有另一方面需要討論:這些分支必須覆蓋了所有的可能性。否則不能進(jìn)行編譯。
fn plus_one(x: Option<i32>) -> Option<i32> {
match x {
Some(i) => Some(i + 1),
}
}
根據(jù)上面錯誤提示,我們知道Rust中match匹配必須是窮盡的,否則無法編譯通過。
2.3?通配模式和 _ 占位符
我們看一下如下示例:
fn main() {
let dice_roll = 9;
match dice_roll {
3 => 3,
7 => 7,
hello => 9,
};
}
3和7會匹配對應(yīng)的值,定義一個變量例如:hello,則可以匹配其他任意情況下的值。
即使我們沒有列出?u8
?所有可能的值,這段代碼依然能夠編譯,因為最后一個模式將匹配所有未被特殊列出的值。這種通配模式滿足了?match
?必須被窮盡的要求。請注意,我們必須將通配分支放在最后,因為模式是按順序匹配的。如果我們在通配分支后添加其他分支,Rust 將會警告我們,因為此后的分支永遠(yuǎn)不會被匹配到。
Rust 還提供了一個模式,當(dāng)我們不想使用通配模式獲取的值時,請使用?_
?,這是一個特殊的模式,可以匹配任意值而不綁定到該值。這告訴 Rust 我們不會使用這個值,所以 Rust 也不會警告我們存在未使用的變量。
fn main() {
let dice_roll = 9;
match dice_roll {
3 => 3,
7 => 7,
_ => 9,
};
}
當(dāng)我們匹配到其他情況,這種情況下我們不想運行任何代碼??梢苑祷匾粋€空元組,如下所示:
fn main() {
let dice_roll = 9;
match dice_roll {
3 => three(),
7 => seven(),
_ => (),
}
fn three() {}
fn seven() {}
}
3、if let 簡潔控制流
我們先看一個示例:
fn main() {
let config_max = Some(3u8);
match config_max {
Some(max) => println!("The maximum is configured to be {}", max),
_ => (),
}
}
如果值是?Some
,我們希望打印出?Some
?成員中的值,這個值被綁定到模式中的?max
?變量里。對于?None
?值我們不希望做任何操作。為了滿足?match
?表達(dá)式(窮盡性)的要求,必須在處理完這唯一的成員后加上?_ => ()
,這樣也要增加很多煩人的樣板代碼。
為了簡化代碼,可以使用if let 來簡化一下:
fn main() {
let config_max = Some(3u8);
if let Some(max) = config_max {
println!("res {}", max)
}
}
使用?if let
?意味著編寫更少代碼,更少的縮進(jìn)和更少的樣板代碼。然而,這樣會失去?match
?強制要求的窮盡性檢查。match
?和?if let
?之間的選擇依賴特定的環(huán)境以及增加簡潔度和失去窮盡性檢查的權(quán)衡取舍。
換句話說,可以認(rèn)為?if let
?是?match
?的一個語法糖,它當(dāng)值匹配某一模式時執(zhí)行代碼而忽略所有其他值。文章來源:http://www.zghlxwxcb.cn/news/detail-756280.html
至于下環(huán)線匹配的模式,可以通過if let else 來實現(xiàn),如下所示:文章來源地址http://www.zghlxwxcb.cn/news/detail-756280.html
fn main() {
let mut count = 0;
let config_max = Some(3u8);
if let Some(max) = config_max {
println!("res {}", max)
} else {
count += 1;
}
}
到了這里,關(guān)于Rust 枚舉和模式匹配的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!