隱私權政策

搜尋此網誌

技術提供:Blogger.

關於我自己

我的相片
目前從事軟體相關行業,喜歡閱讀、健身、喝調酒。習慣把遇到的問題記下來,每天做一些整理方便自己以後查。 Python、Rust、Kotlin等程式語言皆為自學,目前比較著重在Rust語言,歡迎一起討論。

2023年11月21日 星期二

Rust 獲取Option和Result方法 - unwrap五兄弟


Option[1]

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

有兩個值

一個是Some,另一個則是None

用於表示存在數據或不存在數據

例如初始化、函數返回等


Result[2]

    pub enum Result<T, E> {
        Ok(T),
        Err(E),
    }

Result一樣有兩個值

Ok(T)表示操作成功,Err(E)則是操作失敗

用於表示可能成功或失敗的操作

例如文件讀取、網路請求等


獲取值方法

而想要獲得Some或Ok裡面的值

unwrap是一種方法

但unwrap其實有很多種

根據不同場合可以使用不一樣的

有五個我比較常用的

1. unwrap[3]

    pub fn unwrap(self) -> T

最常用的

直接把Some和Ok的值拿出來

但如果出現None以及Err會直接panic

    let x: Result<u32, &str> = Ok(2);
    assert_eq!(x.unwrap(), 2);

這樣可以取出2

    let x: Result<u32, &str> = Err("emergency failure");
    x.unwrap();

如果使用Err,則會panic

panic顯示emergency failure

2. unwrap_or[4]

    pub fn unwrap_or(self, default: T) -> T

unwrap_or需要輸入一個預設值

如果發生None或者Err,則以預設值為主

若沒發生則取出Some或Ok

    let default = 3;
    let ans: Result<i32, &str> = Ok(5);
    assert_eq!(ans.unwrap_or(default), 5);
    let default = 3;
    let ans: Result<i32, &str> = Err("error");
    assert_eq!(ans.unwrap_or(default), 3);

第一次unwrap_or,成功

所以取出的值是5

第二次unwrap_or,失敗

但有輸入預設值,當失敗值會輸出預設值,也就是3

3. unwrap_or_else[5]

    pub fn unwrap_or_else<F>(self, op: F) -> T
    where
        F: FnOnce(E) -> T,

unwrap_or_else,需要輸入一個閉包

要馬回傳Some或Ok,要馬會回傳閉包值

fn get_user_info(user_id: u32) -> Result<&'static str, &'static str> {
    match user_id {
        1 => Ok("User: Alice"),
        2 => Ok("User: Bob"),
        _ => Err("User not found"),
    }
}

fn main() {
    let user_id_to_fetch = 2;
    let user_info = get_user_info(user_id_to_fetch);
    let result = user_info.unwrap_or_else(|err| {
        println!("Error retrieving user info: {}", err);
        "Unknown User"
    });
    println!("User Info: {}", result);
}
User Info: User: Bob

一個例子,透過unwrap_or_else可以處理Err的情況

如果沒有Err,則會回傳正確的值

以範例程式來說,就是回傳人物的名字

如果Err,則會執行閉包內容,閉包元素為Err錯誤訊息

舉個錯誤例子

fn get_user_info(user_id: u32) -> Result<&'static str, &'static str> {
    match user_id {
        1 => Ok("User: Alice"),
        2 => Ok("User: Bob"),
        _ => Err("User not found"),
    }
}

fn main() {
    let user_id_to_fetch = 5;
    let user_info = get_user_info(user_id_to_fetch);
    let result = user_info.unwrap_or_else(|err| {
        println!("Error retrieving user info: {}", err);
        "Unknown User"
    });
    println!("User Info: {}", result);
}
Error retrieving user info: User not found User Info: Unknown User

會先將err訊息列印出來,然後把Unknown User放入result

最後再次印出來

4. unwrap_or_default[6]

    pub fn unwrap_or_default(self) -> T

unwrap_or_default,跟unwrap_or很像

但unwrap_or需要輸入預設值

unwrap_or_default則不需要

會回傳類型的默認值

例如

    let num: Result<i32, i32> = Ok(3);
    let num1: Result<i32, i32> = Err(1);
    println!("success: {}", num.unwrap_or_default());
    println!("error: {}", num1.unwrap_or_default());
success: 3 error: 0

如果是Ok,則直接回傳Ok值

而如果是Err,則回傳型態默認值

i32的默認值是0

因此最後會回傳0

5. unwrap_err[7]

    pub fn unwrap_err(self) -> E

跟上方四個不一樣

這個是要回傳錯誤的值

如果是Ok會panic

例如

fn main() {
    let num: Result<i32, &str> = Err("Something wrong");
    println!("error: {}", num.unwrap_err());
}
error: Something wrong

但如果是這樣

    let num: Result<i32, &str> = Ok(666);
    println!("Ok: {}", num.unwrap_err());
thread 'main' panicked at 'called `Result::unwrap_err()` on an `Ok` value: 666'

Ok反而會直接跳出錯誤訊息


參考資料

[1] https://doc.rust-lang.org/std/option/enum.Option.html

[2] https://doc.rust-lang.org/std/result/enum.Result.html#variant.Err

[3] https://doc.rust-lang.org/std/result/enum.Result.html#method.unwrap

[4] https://doc.rust-lang.org/std/result/enum.Result.html#method.unwrap_or

[5] https://doc.rust-lang.org/std/result/enum.Result.html#method.unwrap_or_else

[6] https://doc.rust-lang.org/std/result/enum.Result.html#method.unwrap_or_default

[7] https://doc.rust-lang.org/std/result/enum.Result.html#method.unwrap_err

0 comments:

張貼留言