Rust Option 模式匹配簡介

Option

Option是rust非常好用的數(shù)據(jù)結(jié)構(gòu)循签,用來解決 Null 空指針問題熄攘,是rust安全基石重要一環(huán)嘁信。其本質(zhì)是一個 Enum 結(jié)構(gòu)。本文對option進(jìn)行模式匹配用于獲取 option 包裝的值的簡單用法抡爹。

Option的聲明:

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

例子:


    let opt = Some("hello".to_string());

    println!("{:?}", opt);  // 輸出: Some("hello")

模式匹配

Option 是一個Enum掩驱,通過模式匹配獲取其變體

Some(T) 變體

    let opt = Some("hello".to_string());
    match opt {
        Some(x) => println!("Some: x={}", x), // Some: x=hello
        None => println!("None")
    }

None 變體

    let opt:Option<String> = None;
    match opt {
        Some(x) => println!("Some: x={}", x), 
        None => println!("None") // None
    }

變量 opt 可以是 None 變體。上面的 opt 需要指定類型冬竟,不然這段代碼編譯器無法推斷 x 的類型欧穴。

unwarp方法

Option 有很多有用的方法。unwarp 方法用于獲取 Some(x) 中 的 x 值泵殴。如果 Option是 None 變體涮帘,則該方法會 pannic。

    let opt = Some("hello".to_string());
    let s = opt.unwrap();
    println!("{}", s); // s

opt 通過 unwarp 方法獲取變體 Some(x) 中的 x笑诅。若 opt 是 None 變體焚辅,unwarp 方法會pannic

uwranp的源碼:

    pub const fn unwrap(self) -> T {
        match self {
            Some(val) => val,
            None => panic!("called `Option::unwrap()` on a `None` value"),
        }
    }

從 unwarp的源碼可以看出映屋,它本質(zhì)也是模式匹配的一種簡寫苟鸯。

所有權(quán)

Option的模式匹配和 unwarp 方法涉及所有權(quán)move語義同蜻。(x指沒有實現(xiàn) Copy trait的類型)

就像賦值,參數(shù)傳遞一樣早处。直接模式匹配會涉及所有權(quán)move

    let opt = Some("hello".to_string());
    match opt {
        Some(x) => println!("Some: x={}", x),  // 模式匹配湾蔓,所有權(quán)move
        None => println!("None") 
    }

    println!("{:?}", opt);  // 所有權(quán)已move

上面的代碼會編譯錯誤。錯誤信息如下:

error[E0382]: borrow of partially moved value: `opt`
  --> src/main.rs:54:22
   |
50 |         Some(x) => println!("Some: x={}", x),
   |              - value partially moved here
...
54 |     println!("{:?}", opt);
   |                      ^^^ value borrowed here after partial move
   |
   = note: partial move occurs because value has type `String`, which does not implement the `Copy` trait
help: borrow this field in the pattern to avoid moving `opt.0`

String 類型是沒有實現(xiàn) Copy trait砌梆,它存儲在堆上默责。創(chuàng)建 opt的時候,它的所有權(quán)move到 opt咸包,通過模式匹配桃序,所有權(quán)move到 x。x在match花括號的作用域后drop了烂瘫。但是 opt 沒有所有權(quán)媒熊,再次打印會報錯。

unwrap 實現(xiàn)基于模式匹配坟比,因此 unwarp 方法也會move 所有權(quán)芦鳍。

    let opt = Some("hello".to_string());
    let s = opt.unwrap();

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

編譯錯誤信息:

48  |     let opt = Some("hello".to_string());
    |         --- move occurs because `opt` has type `Option<String>`, which does not implement the `Copy` trait
49  |     let s = opt.unwrap();
    |                 -------- `opt` moved due to this method call
50  | 
51  |     println!("{:?}", opt);
    |                      ^^^ value borrowed here after move
    |

引用

move語義會轉(zhuǎn)移所有權(quán),使用借用 borrow語義就能保持所有權(quán)葛账。

寫法一


    let opt = Some("hello".to_string());

    match &opt {
        Some(x) => println!("{}", x),     // 對 &opt 進(jìn)行模式匹配,此時的 x 是 &String 類型 
        None => println!("None"),
    }
    println!("{:?}", opt);  // 輸出 Some("hello")

寫法二

    let opt = Some("hello".to_string());

    match opt {
        Some(ref x) => println!("{}", x),
        None => println!("None"),
    }
    println!("{:?}", opt);

opt 依然是正常的形式,不是其引用剃根,在 Some 中使用 ref 修飾 x愕掏,此時 x 是 &String。 即將 opt所有的 String 的引用借給 x

    let opt = Some("hello".to_string());

    let s = &opt.unwrap();
    println!("{:?}", opt);

很不幸趋急,這樣還是會編譯錯誤喝峦。&opt.unwrap(); 實際是 &(opt.unwrap)。所有權(quán)move之后再取引用宣谈。那么很容易想到下面的做法

    let opt = Some("hello".to_string());

    let s = (&opt).unwrap();
    println!("{:?}", opt);

這樣做依然會編譯失敗愈犹。即使是 &opt,unwarp的簽名是 self 闻丑,也就是 傳遞給 unwrap 的是 opt 漩怎,而不是 &opt。所有權(quán)還是轉(zhuǎn)移了嗦嗡。想要實現(xiàn) 所有權(quán)的借用勋锤,可以仿照 上面 match表達(dá)式的寫法。


    let opt = Some("hello".to_string());

    let s = unwrap(&opt); 
    println!("{:?}", s);    // hello
    println!("{:?}", opt);  // Some("hello")


 fn unwrap(opt: &Option<String>) -> &String {
    match opt {
        Some(x) => x,
        None => panic!("called `Option::unwrap()` on a `None` value"),
    }
}
   

as_ref

既然我們能想到封裝一個 unwrap函數(shù)侥祭,標(biāo)準(zhǔn)庫早也想到了叁执。option的as_ref 源碼

    pub const fn as_ref(&self) -> Option<&T> {   // 將 opt 的引用&opt 作為參數(shù)
        match *self {                            // 對 opt 進(jìn)行模式匹配
            Some(ref x) => Some(x),              // 通過 ref 獲取 x 引用茄厘,再封裝成 Option 返回
            None => None,
        }
    }

上面的 Some(ref x) => Some(x) 就是我們上面展示的引用的寫法二。過 as_ref 調(diào)用得到的是 Option<&String>谈宛。再調(diào)用 unwrap方法次哈,就是對其進(jìn)行模式匹配,就是寫法二的方式:

    let opt = Some("hello".to_string());

    let opt1 = opt.as_ref();   // as_ref 獲取 opt x的引用

    match opt1 {                        // 模式匹配
        Some(x) => println!("{}", x),   // x 是 &String 
        None => println!("None"),
    }
    println!("{:?}", opt);
    println!("{:?}", opt1);

上面的過程可以連起來寫成一行

    let opt = Some("hello".to_string());

    let s = opt.as_ref().unwrap();
    println!("{:?}", s);
    println!("{:?}", opt);

總結(jié)

Option<T> 是 rust 類型安全重要思想的體現(xiàn)之一吆录。它本質(zhì)是一個 Enum 類型窑滞,有兩個變體,Some(x) 和 None恢筝。當(dāng)表示沒有值的時候哀卫,可以使用 None。其語義類似其他語言如 Python的None撬槽,Golang 的 nil此改, java 的null。但是又跟其他語言有本質(zhì)的不同侄柔。rust 的 None 是 Option 類型共啃。而不是 其他任何類型。而其他語言的 None nil 可以是任何其他類型或引用類型勋拟。Null 可以是 字串勋磕,也可以是 指針。這就埋下了很多安全隱患敢靡。

Rust 的中表示可有可無的時候使用 Option挂滓。有值的時候需要使用 Some 變體。解出 Some(x) 中的 x 值方法是模式匹配啸胧。同時標(biāo)注庫也提供了便捷方法如 unwrap赶站。

無論是使用 模式匹配 還是一些方法,對于所有權(quán)的move還是borrow嚴(yán)格遵循rust的所有權(quán)系統(tǒng)纺念。通過上面介紹的幾個例子用以說明贝椿。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市陷谱,隨后出現(xiàn)的幾起案子烙博,更是在濱河造成了極大的恐慌,老刑警劉巖烟逊,帶你破解...
    沈念sama閱讀 206,013評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件渣窜,死亡現(xiàn)場離奇詭異,居然都是意外死亡宪躯,警方通過查閱死者的電腦和手機(jī)乔宿,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,205評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來访雪,“玉大人详瑞,你說我怎么就攤上這事掂林。” “怎么了坝橡?”我有些...
    開封第一講書人閱讀 152,370評論 0 342
  • 文/不壞的土叔 我叫張陵泻帮,是天一觀的道長。 經(jīng)常有香客問我驳庭,道長刑顺,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,168評論 1 278
  • 正文 為了忘掉前任饲常,我火速辦了婚禮,結(jié)果婚禮上狼讨,老公的妹妹穿的比我還像新娘贝淤。我一直安慰自己,他們只是感情好政供,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,153評論 5 371
  • 文/花漫 我一把揭開白布播聪。 她就那樣靜靜地躺著,像睡著了一般布隔。 火紅的嫁衣襯著肌膚如雪离陶。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 48,954評論 1 283
  • 那天衅檀,我揣著相機(jī)與錄音招刨,去河邊找鬼。 笑死哀军,一個胖子當(dāng)著我的面吹牛沉眶,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播杉适,決...
    沈念sama閱讀 38,271評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼谎倔,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了猿推?” 一聲冷哼從身側(cè)響起片习,我...
    開封第一講書人閱讀 36,916評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎蹬叭,沒想到半個月后藕咏,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,382評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡具垫,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,877評論 2 323
  • 正文 我和宋清朗相戀三年侈离,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片筝蚕。...
    茶點(diǎn)故事閱讀 37,989評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡卦碾,死狀恐怖铺坞,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情洲胖,我是刑警寧澤济榨,帶...
    沈念sama閱讀 33,624評論 4 322
  • 正文 年R本政府宣布,位于F島的核電站绿映,受9級特大地震影響擒滑,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜叉弦,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,209評論 3 307
  • 文/蒙蒙 一丐一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧淹冰,春花似錦库车、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,199評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至晶乔,卻和暖如春珍坊,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背正罢。 一陣腳步聲響...
    開封第一講書人閱讀 31,418評論 1 260
  • 我被黑心中介騙來泰國打工阵漏, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人腺怯。 一個月前我還...
    沈念sama閱讀 45,401評論 2 352
  • 正文 我出身青樓袱饭,卻偏偏與公主長得像,于是被迫代替她去往敵國和親呛占。 傳聞我的和親對象是個殘疾皇子虑乖,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,700評論 2 345

推薦閱讀更多精彩內(nèi)容