- Rust 教程
- Rust - 首頁
- Rust - 簡介
- Rust - 環境設定
- Rust - HelloWorld 示例
- Rust - 資料型別
- Rust - 變數
- Rust - 常量
- Rust - 字串
- Rust - 運算子
- Rust - 決策
- Rust - 迴圈
- Rust - 函式
- Rust - 元組
- Rust - 陣列
- Rust - 所有權
- Rust - 借用
- Rust - 切片
- Rust - 結構體
- Rust - 列舉
- Rust - 模組
- Rust - 集合
- Rust - 錯誤處理
- Rust - 泛型
- Rust - 輸入輸出
- Rust - 檔案輸入/輸出
- Rust - 包管理器
- Rust - 迭代器和閉包
- Rust - 智慧指標
- Rust - 併發
- Rust 有用資源
- Rust - 快速指南
- Rust - 有用資源
- Rust - 討論
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> 可用於處理可恢復錯誤。它有兩個變體:OK 和 Err。T 和 E 是泛型型別引數。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 並返回其中包含的值。如果它改為Err或None,則它會引發 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.