Rust 基礎知識23 - 模式匹配

模式匹配

  • 模式匹配通常由一下組件組成:

字面量碑诉。

解構的數(shù)組太示、枚舉、結構體或者元組帮孔。

變量雷滋。

通配符

占位符。

知識匯總

模式的不可失敗性和可失敗性

  • 模式可以被分為不可失敗(irrefutable) 和可失敗(refutable)兩種類型文兢。
  • 例如 let x = 5; 中的 x 便是不可失敗模式晤斩,因為它能夠匹配表達式右側的所有可能的返回值。
  • 例如 if let Some(x) = a_value 中的 Some(x) 便是可失敗模式禽作,如果 a_value 變量的值時 None 而不是 Some尸昧,那么表達式左側的Some(x) 模式就會發(fā)生不匹配。
  • 了解這些概念十分重要旷偿,比如 let Some(x) = a_value 就會造成編譯困擾烹俗,因為這個表達式是可失敗的那么就要放到 if 中去。

if let 表達式

  • 舉例:
fn main() {
    let favorite_color: Option<&str> = None;
    let is_tuesday = false;
    let age : Result<u8, _> = "34".parse();

    if let Some(color) = favorite_color {
        println!("Using your favorite color, {}, as the background", color);
    } else if is_tuesday {
        println!("Tuesday is green day!");
    } else if let Ok(age) = age {
        if age > 30 {
            println!("Using purple as the background color");
        } else {
            println!("Using orange as the background color");
        }
    }
}

while let 條件循環(huán)模式匹配

  • 例子:while let 會反復執(zhí)行同一個模式匹配直到出現(xiàn)失敗的情況萍程。

fn main() {
    let mut stack = Vec::new();
    stack.push(1);
    stack.push(2);
    stack.push(3);
    while let Some(s) = stack.pop() {
        println!("Stack value : {}", s);
    }
}

for 循環(huán)進行元祖填充

  • 例子:注意不要忘記調用 enumerate 生成一個元祖迭代器

fn main() {
    let v = vec!["a", "b", "c"];
    for (index, value) in v.iter().enumerate() {
        println!("index : {}, value : {}",index, value );
    }
}

let 關鍵字本身就是一種模式匹配的方式

  • 例子:
// 如果模式元素中的數(shù)量與元祖的數(shù)量不符幢妄,那么就會導致匹配失敗。
let (x, y, z) = (1, 2, 3);
// 如果確實有的不需要茫负,可以通過 _ 或者 .. 進行省略
let (x, y, _) = (1, 2, 3);

函數(shù)參數(shù)也是模式匹配

  • 可以看到模式匹配無處不在蕉鸳,函數(shù)的參數(shù)也是模式匹配。
  • 例子:
// 實際上定義了一個元祖參數(shù)
fn print_coordinates(&(x, y): &(i32, i32)) {
    println!(" Current location : ({}, {})", x, y);
}

fn main() {
    let point = (55, 33);
    print_coordinates(&point);
}

匹配字面量

  • 例子:
fn main() {
    let x = 1 ;
    match x {
        1 => {println!("One"); },
        2 => {println!("Two"); },
        // 注意下面必須加上如果不加會提示沒有窮盡所有解
        _ => {println!("Other"); },
    }
}

匹配命名變量

  • 例子:
fn main() {
    let x = Some(5);
    let y = 10 ;
    match x {
        Some(50) => println!("Get 50"),
        Some(y) => println!("Matched, y = {:?}", y ),
        _ => println!("Default case, x = {:?}", x),
    }

    println!("at the end : x = {:?}, y = {:?}", x, y);
}

多重匹配

  • 例子:
fn main() {
    let x = 1 ;
    match x {
        1 | 2 => println!("one or two"),
        3 => println!("three"),
        _ => println!("anything."),
    }
}

使用 ... 來匹配區(qū)間

  • 例子:
fn main() {
    let x = 7;
    match x {
        1 ... 9 => println!("one through nine"),
        3 => println!("three"),
        _ => println!("anything."),
    }
}

使用 ..= 來匹配字符區(qū)間

  • 例子:
fn main() {
    let x = 'c';
    match x {
        'a' ..= 'd' => println!("a | b | c | d"),
        'f' ..= 'i' => println!("f | g | h | i"),
        _ => println!("anything."),
    }
}

使用解構來分解值(分解結構)

  • 例子:
fn main() {

    struct Point {
        x: i32,
        y: i32,
    }

    let point = Point {
        x: 32,
        y: 66
    };

    // 解構
    let Point {x : a, y : b } = point;
    println!("x:{} , y:{}", a,  b);
}

稍稍復雜一點的match 匹配

  • 看了這個例子突然感覺模式匹配很有用忍法,會的:
fn main() {
    struct Point {
        x: i32,
        y: i32,
    }
    let point = Point {
        x: 0,
        y: 7
    };
    // 進行更復雜一點的模式匹配
    match point {
        Point{x, y:0} => println!("On the x axis at {}", x),
        Point{x:0, y} => println!("On the y axis at {}", y),
        // 注意如下最不能缺少的就是這個潮尝,沒有這個兜底,那么匹配就不能窮盡饿序。
        Point{x,y} => println!("On neither axis: ({}, {})", x,y),
    }
}

解構嵌套的結構體和枚舉:

  • 例子:
enum Color {
    Rgb (i32,i32,i32),
    Hvs (i32,i32,i32),
}

enum Message {
    Quit,
    Write(String),
    ChangeColor(Color),
}

fn main() {
    let msg = Message::ChangeColor(Color::Rgb(6,6,6));
    match msg {
        Message::ChangeColor(Color::Rgb(r,g,b)) => {
            println!("r={},g={},b={}", r,g,b);
        },
        Message::ChangeColor(Color::Hvs(h,v,s)) => {
            println!("h={},v={},s={}", h,v,s);
        },
        _ => {}
    }
}

使用 _ (下劃線) 忽略變量值時需要特別注意的一個問題

  • 例子勉失,錯誤的

fn main() {
    let s = Some(String::from("Hello."));
    if let(_s) = s {
        println!("Hello , into there.")
    }
    // 這段代碼編譯不過去,雖然 _s 但是所有權仍然會轉移
    println!("s value is : {:?} ", s);
}

  • 例子原探,正確的乱凿,_ 單純的下滑線就不會造成所有權轉移顽素,稍稍修改一下。
fn main() {
    let s = Some(String::from("Hello."));
    // 修改一下這里徒蟆,去掉 _ 后面的任何值胁出,所有權就不會轉移。
    if let(_) = s {
        println!("Hello , into there.")
    }
    println!("s value is : {:?} ", s);
}

使用 .. (雙點) 忽略匹配值

  • 例子:

struct Point {
    x: i32, y:i32 , z:i32,
}

fn main() {
    let p = Point {x:3,y:4,z:5};
    // 如果只是想匹配x 可以使用雙點語法段审。
    let Point{x, ..} = p;
    assert_eq!(3, x);
}

為了匹配更復雜的模式可以使用match guard

  • 就是在模式匹配中新增一個 if 條件全蝶,舉例:
fn main() {
    let num = Some(4);
    match num {
        Some(x) if x < 5 => { println!("Num {} less than five. ", x) },
        Some(x) => { println!("Num is {} . ", x) },
        None => {},
    }
}


  • 注意一個情況:
match x {
    4 | 5 | 6 if y => { ... } 
}

實際上等于

match x {
    (4 | 5 | 6) if y => { ... }
    // 而不是 
    4 | 5 | (6 if y) => { ... }
}

模式匹配中的綁定

  • 有些范圍匹配即便成功了,我們也無法捕獲到底是什么值匹配成功的戚哎。
  • 這時候就需要在匹配中綁定變量需要通過 @ 運算符裸诽。
fn main() {
    enum Message {
        Hello {id: i32}
    }

    let msg = Message::Hello {id: 5};

    match msg {
        // 注意這里,如果不用 id_variable@ 進行變量捕獲型凳,下面的println 就無法直到具體的值是什么丈冬。
        Message::Hello {id: id_variable@ 3..=7} => {
            println!("Found an id in range : {} ", id_variable);
        },
        Message::Hello {id:10...12} => {
            println!("Found id between 10 to 12");
        },
        Message::Hello {id} => {
            println!("Found some other id : {}", id);
        },
    }
}

結束

  • 感謝閱讀,See you at work.
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末甘畅,一起剝皮案震驚了整個濱河市埂蕊,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌疏唾,老刑警劉巖蓄氧,帶你破解...
    沈念sama閱讀 217,185評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異槐脏,居然都是意外死亡喉童,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評論 3 393
  • 文/潘曉璐 我一進店門顿天,熙熙樓的掌柜王于貴愁眉苦臉地迎上來堂氯,“玉大人,你說我怎么就攤上這事牌废⊙拾祝” “怎么了?”我有些...
    開封第一講書人閱讀 163,524評論 0 353
  • 文/不壞的土叔 我叫張陵鸟缕,是天一觀的道長晶框。 經常有香客問我,道長懂从,這世上最難降的妖魔是什么授段? 我笑而不...
    開封第一講書人閱讀 58,339評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮番甩,結果婚禮上畴蒲,老公的妹妹穿的比我還像新娘。我一直安慰自己对室,他們只是感情好模燥,可當我...
    茶點故事閱讀 67,387評論 6 391
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著掩宜,像睡著了一般蔫骂。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上牺汤,一...
    開封第一講書人閱讀 51,287評論 1 301
  • 那天辽旋,我揣著相機與錄音,去河邊找鬼檐迟。 笑死补胚,一個胖子當著我的面吹牛,可吹牛的內容都是我干的追迟。 我是一名探鬼主播溶其,決...
    沈念sama閱讀 40,130評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼敦间!你這毒婦竟也來了瓶逃?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 38,985評論 0 275
  • 序言:老撾萬榮一對情侶失蹤廓块,失蹤者是張志新(化名)和其女友劉穎厢绝,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體带猴,經...
    沈念sama閱讀 45,420評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡昔汉,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,617評論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了拴清。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片靶病。...
    茶點故事閱讀 39,779評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖贷掖,靈堂內的尸體忽然破棺而出嫡秕,到底是詐尸還是另有隱情,我是刑警寧澤苹威,帶...
    沈念sama閱讀 35,477評論 5 345
  • 正文 年R本政府宣布昆咽,位于F島的核電站,受9級特大地震影響牙甫,放射性物質發(fā)生泄漏掷酗。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,088評論 3 328
  • 文/蒙蒙 一窟哺、第九天 我趴在偏房一處隱蔽的房頂上張望泻轰。 院中可真熱鬧,春花似錦且轨、人聲如沸浮声。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,716評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽泳挥。三九已至然痊,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間屉符,已是汗流浹背剧浸。 一陣腳步聲響...
    開封第一講書人閱讀 32,857評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留矗钟,地道東北人唆香。 一個月前我還...
    沈念sama閱讀 47,876評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像吨艇,于是被迫代替她去往敵國和親躬它。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,700評論 2 354

推薦閱讀更多精彩內容

  • if case 在學習 if case之前秸应,我們先想想虑凛,那些地方使用到了case 這個關鍵字,毫無疑問软啼,絕大多數(shù)使...
    楓葉1234閱讀 2,317評論 0 3
  • 通用編程概念 變量與可變性 變量默認不可變桑谍,如需要改變,可在變量名前加 mut 使其可變祸挪。例如:let mut a...
    soojade閱讀 12,567評論 2 30
  • 01-前端開發(fā)和前端開發(fā)工具 一锣披、前端開發(fā) PRD(產品原型-產品經理) - PSD(視覺設計-UI工程師) - ...
    刊ing閱讀 244評論 0 0
  • Swift里的switch比OC里面強大很多,switch的主要特性就是模式匹配贿条。下面先舉個非常簡單的例子雹仿。 看完...
    ChoiKarl閱讀 2,128評論 3 11
  • Scala強大的模式匹配機制,可以應用在switch語句整以、類型檢查以及“析構”等場合胧辽。樣本類對模式匹配進行了優(yōu)化。...
    彤慶閱讀 499評論 0 1