iT邦幫忙

2023 iThome 鐵人賽

DAY 10
0

平常我們寫網頁的時候,也會有錯誤的 exception 處理,
避免錯誤發生的時候出現非預期的畫面

Rust 中也有 Error Handling 的機制

為什麼要有 error handling ?

在開發時,難免都會有錯誤的程式碼,

有錯誤處理機制是為了預防我們將程式碼部署到正式環境後,出現錯誤的狀況,

像是預先處理、預防的概念,

而這樣的機制對於開發者算是好事,

寧可在開發時把錯誤處理,也不希望到正式環境錯誤一大堆。

那我們就來看看 Rust 怎麼處理錯誤吧

這邊我們要分成 unrecoverable 以及 recoverable 的兩種,我們先來介紹第一種

unrecoverable

指的是當錯誤發生時,後面的程式碼都不會編譯,就中斷在這邊,會以 unrecoverable 來處理錯誤時,通常都是程式碼裡面有 bug,希望開發者能將這個問題處理好,否則就無法繼續編譯或執行

unrecoverable 主要是使用 panic! 這個方法來處理

panic! 是一種 macro ,通常會在程式碼錯誤的時候呼叫 panic! ,讓程式碼無法繼續編譯或執行,這其實有點像是安全機制,告訴你病毒在哪裡,趕快去消滅它!

fn main() {
    println!("Hey, Error will happen!");

    // Explicitly exit the program with an unrecoverable error
    panic!("Crash");
    println!("Can you see me?");
}

當我們執行時,就會出現 thread 'main' panicked at 'Crash', src/main.rs:5:5

我們來解析一下他的意思

thread 的意思是,錯誤是發生在哪裡,主執行序是在 main() 執行,所以就是 thread 'main'

panicked 指的是錯誤發生在哪裡,並且指出在程式碼的哪一行

> cargo run

Hey, Error will happen!
thread 'main' panicked at 'Crash', src/main.rs:5:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

讓我們再來看看一個例子,我們要印出陣列 index 2 的值
(可是其實沒有 index 2)

fn main() {
    let a = [1, 2];
    println!("這個陣列最後一個值是 {:?}", a[2]);

    println!("Can you see me?");
}

當我們執行時,他會直接噴錯,連編譯都無法

> cargo run

  Compiling hello_world v0.1.0 (/Users/zhangjianing/Desktop/Side Project/rust_practice/hello_world)
error: this operation will panic at runtime
 --> src/main.rs:4:33
  |
4 |     println!("這個陣列最後一個值是 {:?}", a[2]);
  |                                           ^^^^ index out of bounds: the length is 2 but the index is 2
  |
  = note: `#[deny(unconditional_panic)]` on by default

error: could not compile `hello_world` (bin "hello_world") due to previous error

在 C 語言中,當我們要取出的 index 值是陣列沒有的,有可能會取到整個記憶體中的 index ,即便這個值不是屬於該陣列的,如果有人蓄意要攻擊,就可能會導致安全性問題

而 Rust 為了避免這樣的狀況發生,就會讓 panic! 發出錯誤警告,並且避免程式繼續執行下去

recoverable

這邊就比較少是 bug 問題,通常都是操作上的問題,像是文件遺失、無權限、型態解析錯誤等等

在 Rust 中會用 Result 以及 Option 來處理 recoverable

Result

Result<T, E> 來表示結果是成功還是失敗,需要兩個參數,一個是 T,一個是 E,其實這兩個參數是

T 代表著成功後回傳的變數
E 則是失敗回傳的錯誤訊息

我們之後會再討論 TE

來看看應用的例子,我今天要去解析字串成數字,就可以用 Result 去看是否可以解析成功,以下是解析成功的例子

fn main() {
    let number: Result<i32, _> = "123".parse();

    match number {
        Ok(num) => println!("解析成功:{}", num),
        Err(error) => println!("無法解析:{}", error),
    }
}

編譯並且執行後,會執行 Ok 這條

> cargo run

Compiling hello_world v0.1.0 (/Users/zhangjianing/Desktop/Side Project/rust_practice/hello_world)
Finished dev [unoptimized + debuginfo] target(s) in 0.27s
Running `target/debug/hello_world`
解析成功:123

如果是失敗的例子呢?他就會走 Err 這條

fn main() {
    let number: Result<i32, _> = "一二三".parse();

    match number {
        Ok(num) => println!("解析成功:{}", num),
        Err(error) => println!("無法解析:{}", error),
    }
}

編譯並且執行後

> cargo run

Finished dev [unoptimized + debuginfo] target(s) in 0.04s
Running `target/debug/hello_world`
無法解析:invalid digit found in string

剛剛有看到一個 match 的東西,我們可以把 match 看作是一個語法糖衣,如果沒有 match ,我們就需要用 panic! 來呈現錯誤訊息

Option

Option<T> 適用於此變數或者結果是否存在,會有 None 以及 Some 這兩個結果

這邊的 T 跟 Result 不太一樣,可能會是 Some 或者是 None,不過他們都是參數

Some(c) 表示存在,並且回傳 c (不一定要叫 c ,想叫什麼都可)變數
None 表示不存在

讓我們來看看例子吧

fn main() {
    let a = [1, 2, 3];
    let b = a.get(2);

    let _c = match b {
        None => println!("沒有這個值"),
        Some(c) => println!("結果為:{}", c),
    };
}

編譯並執行後,會得到 c

> cargo run

Compiling hello_world v0.1.0 (/Users/zhangjianing/Desktop/Side Project/rust_practice/hello_world)
Finished dev [unoptimized + debuginfo] target(s) in 0.15s
Running `target/debug/hello_world`
結果為:3

那如果值不存在呢?

fn main() {
    let a = [1, 2, 3];
    let b = a.get(3);

    let _c = match b {
        None => println!("沒有這個值"),
        Some(c) => println!("{}", c),
    };
}

編譯並且執行後,就會走 None 這條

> cargo run

Compiling hello_world v0.1.0 (/Users/zhangjianing/Desktop/Side Project/rust_practice/hello_world)
Finished dev [unoptimized + debuginfo] target(s) in 0.09s
Running `target/debug/hello_world`
沒有這個值

ResultOption 在應用上其實不太一樣,

Result 著重在結果是成功還是失敗
Option 主要應用在這個東西是否存在

不過他們兩個都會與 match 來做搭配應用


上一篇
Day 09 Cargo 與 Crate
下一篇
Day 11 unwrap 跟 expect
系列文
成為程式界的 F1 賽車手,用 30 天認識 Rust 30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言