<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
Rust 有一套獨特的處理異常情況的機制,它並不像其它語言中的 try 機制那樣簡單。
在Rust 中的錯誤分為兩大類:可恢復錯誤和不可恢復錯誤。大多數程式語言用 Exception
(異常)類來表示錯誤。在 Rust 中沒有 Exception。對於可恢復錯誤用 Result<T, E>
類來處理,對於不可恢復錯誤使用 panic!
宏來處理。
1、不可恢復錯誤
宏的使用較為簡單,讓我們來看一個具體例子:
fn main() { panic!("Error occured"); println!("Hello, rust"); }
執行結果:
很顯然,程式並不能如約執行到 println!("Hello, rust")
,而是在 panic!
宏被呼叫時停止了執行,不可恢復的錯誤一定會導致程式受到致命的打擊而終止執行。
我們來分析一下終端命令列中的報錯資訊:
thread 'main' panicked at 'Error occured', srcmain.rs:2:5
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
RUST_BACKTRACE=full
環境變數執行以顯示回溯"。接下來看一下回溯(backtrace
)資訊:
stack backtrace:
0: std::panicking::begin_panic_handler
at /rustc/e092d0b6b43f2de967af0887873151bb1c0b18d3/librarystdsrcpanicking.rs:584
1: core::panicking::panic_fmt
at /rustc/e092d0b6b43f2de967af0887873151bb1c0b18d3/librarycoresrcpanicking.rs:142
2: error_deal::main
at .srcmain.rs:2
3: core::ops::function::FnOnce::call_once<void (*)(),tuple$<> >
at /rustc/e092d0b6b43f2de967af0887873151bb1c0b18d3librarycoresrcopsfunction.rs:248
回溯是不可恢復錯誤的另一種處理方式,它會展開執行的棧並輸出所有的資訊,然後程式依然會退出。通過大量的輸出資訊,我們可以找到我們編寫的 panic! 宏觸發的錯誤。
此概念十分類似於 Java 程式語言中的異常,而在 C 語言中我們就常常將函數返回值設定成整數來表達函數遇到的錯誤,在 Rust 中通過 Result<T, E>
列舉類作返回值來進行異常表達:
enum Result<T, E> { Ok(T), Err(E), }//T的型別不定,相當於C++中模板的寫法
我們知道
enum
常常與match
配合使用,當匹配到OK
時就會執行相應程式碼。
在 Rust 標準庫中可能產生異常的函數的返回值都是 Result
型別。
例如:當我們嘗試開啟一個檔案時:
use std::fs::File; fn main() { let fp = File::open("hello_rust.txt"); match fp { Ok(file) => { println!("File opened successfully."); }, Err(err) => { println!("Failed to open the file."); } } }//OK裡的引數file是File型別,相當於填充了列舉裡的T型別
如果
hello_rust.txt
檔案不存在,會列印 Failed to open the file.
當然,我們在列舉類章節講到的 if let
模式匹配語法可以簡化 match
語法塊:
use std::fs::File; fn main() { let fp = File::open("hello_rust.txt"); if let Ok(file) = fp { println!("File opened successfully."); } else { println!("Failed to open the file."); } }
將一個可恢復錯誤按不可恢復錯誤處理
舉個例子:
use std::fs::File; fn main() { let fp1 = File::open("hello_rust.txt").unwrap(); let fp2 = File::open("hello_rust.txt").expect("Failed to open."); }
Err
時呼叫 panic!宏expect
能夠向 panic! 宏傳送一段指定的錯誤資訊panic!
宏是不可恢復錯誤,這樣就完成了轉變之前所講的是接收到錯誤的處理方式,接下來講講怎麼把錯誤資訊傳遞出去
我們先來編寫一個函數:
fn f(i: i32) -> Result<i32, bool> { if i >= 0 { Ok(i) } else { Err(false) } } fn main() { let r = f(10000); if let Ok(v) = r { println!("Ok: f(-1) = {}", v); } else { println!("Err"); } }//執行結果:Ok: f(-1) = 10000
這裡
r
的結果是f
函數返回的ok(10000)
,經過if let
模式匹配後v
的值為10000
這段程式中函數 f
是錯誤的根源,現在我們再寫一個傳遞錯誤的函數 g
:
fn g(i: i32) -> Result<i32, bool> { let t = f(i); return match t { Ok(i) => Ok(i), Err(b) => Err(b) }; }
函數 g 傳遞了函數 f 可能出現的錯誤,這樣寫有些冗長,Rust 中可以在 Result 物件後新增 ?
操作符將同類的 Err
直接傳遞出去:
fn f(i: i32) -> Result<i32, bool> { if i >= 0 { Ok(i) } else { Err(false) } } fn g(i: i32) -> Result<i32, bool> { let t = f(i)?; Ok(t) // 因為確定 t 不是 Err, t 在這裡已經推匯出是 i32 型別 } fn main() { let r = g(10000); if let Ok(v) = r { println!("Ok: g(10000) = {}", v); } else { println!("Err"); } }//執行結果:Ok: g(10000) = 10000
?
符的實際作用是將 Result 類非異常的值直接取出,如果有異常就將異常 Result 返回出去。所以? 符僅用於返回值型別為 Result<T, E> 的函數,且其中E
型別必須和?
所處理的 Result 的 E 型別一致。
雖然前面提到Rust 異常不像其他語言這麼簡單,但這並不意味著 Rust 實現不了:我們完全可以把 try
塊在獨立的函數中實現,將所有的異常都傳遞出去解決。
實際上這才是一個分化良好的程式應當遵循的程式設計方法:應該注重獨立功能的完整性。
但是這樣需要判斷 Result 的 Err 型別,獲取 Err 型別的函數是 kind()
做一個開啟檔案的範例:
use std::io; use std::io::Read; use std::fs::File; fn read_text_from_file(path: &str) -> Result<String, io::Error> { let mut f = File::open(path)?; let mut s = String::new(); f.read_to_string(&mut s)?; Ok(s) } fn main() { let str_file = read_text_from_file("hello_rust.txt"); match str_file { Ok(s) => println!("{}", s), Err(e) => { match e.kind() { io::ErrorKind::NotFound => { println!("No such file"); }, _ => { println!("Cannot read the file"); } } } } }//這裡我沒有建立hello_rust.txt檔案,因此執行結果為:No such file
程式碼解釋:
read_text_from_file()
函數將檔案開啟的結果傳給了str_file
變數hello_rust.txt
,因此File::open(path)?
不會開啟檔案,異常會存到f
中f.read_to_string(&mut s)?
並不能讀出檔案內容,ok(s)
無內容Err(e)
的程式碼塊,使用e.kind()
得到了錯誤型別並再次進行match
分支NotFound
錯誤就會列印No such file到此這篇關於Rust指南錯誤的分類與傳遞|使用kind進行例外處理的文章就介紹到這了,更多相關Rust錯誤處理內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45