Rust - 錯誤處理



在 Rust 中,錯誤可以分為以下兩大類,如下表所示。

序號 名稱及描述 用法
1

可恢復

可以處理的錯誤

Result 列舉
2

不可恢復

無法處理的錯誤

panic 宏

可恢復錯誤是可以糾正的錯誤。當程式遇到可恢復錯誤時,可以重試失敗的操作或指定備用操作方案。可恢復錯誤不會導致程式突然失敗。可恢復錯誤的一個示例是檔案未找到錯誤。

不可恢復錯誤會導致程式突然失敗。如果發生不可恢復錯誤,程式無法恢復到其正常狀態。它無法重試失敗的操作或撤消錯誤。不可恢復錯誤的一個示例是嘗試訪問陣列末尾以外的位置。

與其他程式語言不同,Rust 沒有異常。它為可恢復錯誤返回一個列舉Result<T, E>,而在程式遇到不可恢復錯誤時,它會呼叫panic宏。panic宏會導致程式突然退出。

Panic 宏和不可恢復錯誤

panic!宏允許程式立即終止並向程式的呼叫者提供反饋。當程式達到不可恢復狀態時,應使用它。

fn main() {
   panic!("Hello");
   println!("End of main"); //unreachable statement
}

在上面的示例中,當程式遇到panic!宏時,它將立即終止。

輸出

thread 'main' panicked at 'Hello', main.rs:3

示例:panic! 宏

fn main() {
   let a = [10,20,30];
   a[10]; //invokes a panic since index 10 cannot be reached
}

輸出如下所示:

warning: this expression will panic at run-time
--> main.rs:4:4
  |
4 | a[10];
  | ^^^^^ index out of bounds: the len is 3 but the index is 10

$main
thread 'main' panicked at 'index out of bounds: the len 
is 3 but the index is 10', main.rs:4
note: Run with `RUST_BACKTRACE=1` for a backtrace.

如果違反業務規則,程式可以呼叫panic!宏,如下面的示例所示:

fn main() {
   let no = 13; 
   //try with odd and even
   if no%2 == 0 {
      println!("Thank you , number is even");
   } else {
      panic!("NOT_AN_EVEN"); 
   }
   println!("End of main");
}

如果分配給變數的值為奇數,則以上示例返回錯誤。

輸出

thread 'main' panicked at 'NOT_AN_EVEN', main.rs:9
note: Run with `RUST_BACKTRACE=1` for a backtrace.

Result 列舉和可恢復錯誤

列舉 Result – <T,E> 可用於處理可恢復錯誤。它有兩個變體:OKErrTE 是泛型型別引數。T 表示在成功情況下將在 OK 變體中返回的值的型別,E 表示在失敗情況下將在 Err 變體中返回的錯誤的型別。

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

讓我們藉助一個示例來理解這一點:

use std::fs::File;
fn main() {
   let f = File::open("main.jpg"); 
   //this file does not exist
   println!("{:?}",f);
}

如果檔案已存在,則程式返回OK(File),如果檔案未找到,則返回Err(Error)

Err(Error { repr: Os { code: 2, message: "No such file or directory" } })

現在讓我們看看如何處理 Err 變體。

以下示例使用match語句處理開啟檔案時返回的錯誤

use std::fs::File;
fn main() {
   let f = File::open("main.jpg");   // main.jpg doesn't exist
   match f {
      Ok(f)=> {
         println!("file found {:?}",f);
      },
      Err(e)=> {
         println!("file not found \n{:?}",e);   //handled error
      }
   }
   println!("end of main");
}

注意 - 即使檔案未找到,程式也會列印main事件的結束。這意味著程式已優雅地處理了錯誤。

輸出

file not found
Os { code: 2, kind: NotFound, message: "The system cannot find the file specified." }
end of main

示例

is_even函式如果數字不是偶數則返回錯誤。main()函式處理此錯誤。

fn main(){
   let result = is_even(13);
   match result {
      Ok(d)=>{
         println!("no is even {}",d);
      },
      Err(msg)=>{
         println!("Error msg is {}",msg);
      }
   }
   println!("end of main");
}
fn is_even(no:i32)->Result<bool,String> {
   if no%2==0 {
      return Ok(true);
   } else {
      return Err("NOT_AN_EVEN".to_string());
   }
}

注意 - 由於 main 函式優雅地處理了錯誤,因此列印了main語句的結束

輸出

Error msg is NOT_AN_EVEN
end of main

unwrap() 和 expect()

標準庫包含幾個輔助方法,Result<T,E>和 Option<T>列舉都實現了這些方法。您可以使用它們來簡化您確實不希望出現故障的錯誤情況。如果方法成功,則使用“unwrap”函式提取實際結果。

序號 方法 簽名及描述
1 unwrap

unwrap(self): T

期望 self 為 Ok/Some 並返回其中包含的值。如果它改為ErrNone,則它會引發 panic 並顯示錯誤的內容。

2 expect

expect(self, msg: &str): T

行為類似於 unwrap,除了在出現 panic 之前除了錯誤內容之外還會輸出自定義訊息。

unwrap()

unwrap()函式在操作成功時返回實際結果。如果操作失敗,它會返回帶有預設錯誤訊息的 panic。此函式是 match 語句的簡寫。這在下面的示例中顯示:

fn main(){
   let result = is_even(10).unwrap();
   println!("result is {}",result);
   println!("end of main");
}
fn is_even(no:i32)->Result<bool,String> {
   if no%2==0 {
      return Ok(true);
   } else {
      return Err("NOT_AN_EVEN".to_string());
   }
}
result is true
end of main

修改以上程式碼以將奇數傳遞給is_even()函式。

unwrap()函式將出現 panic 並返回如下所示的預設錯誤訊息

thread 'main' panicked at 'called `Result::unwrap()` on 
an `Err` value: "NOT_AN_EVEN"', libcore\result.rs:945:5
note: Run with `RUST_BACKTRACE=1` for a backtrace

expect()

程式可以在出現 panic 的情況下返回自定義錯誤訊息。這在以下示例中顯示:

use std::fs::File;
fn main(){
   let f = File::open("pqr.txt").expect("File not able to open");
   //file does not exist
   println!("end of main");
}

expect()函式類似於unwrap()。唯一的區別是可以使用 expect 顯示自定義錯誤訊息。

輸出

thread 'main' panicked at 'File not able to open: Error { repr: Os 
{ code: 2, message: "No such file or directory" } }', src/libcore/result.rs:860
note: Run with `RUST_BACKTRACE=1` for a backtrace.
廣告

© . All rights reserved.