rust學習筆記 錯誤處理

2021-10-09 02:12:48 字數 4072 閱讀 7987

rust的錯誤分兩種:

rust提供了可恢復錯誤的型別result< t,e >,與不可恢復錯誤時終止執行的panic!巨集。

程式會在panic!巨集執行時列印出一段錯誤提示資訊,展開並清理當前的呼叫棧,然後退出程式,這種情況大部分都發生在某個錯誤被檢測到,但程式設計師卻不知道該如何處理的時候。

panic的棧展開與終止

panic發生時,程式缺省會開始棧展開,就是會沿著函式呼叫的反向順序清理函式中的資料,為了支援這種操作,我們需要在二進位制中儲存許多額外資訊。

除了棧展開我們還可以選擇立即終止,讓作業系統來進行**工作。你可以在cargo.toml中的[profile]裡設定panic=『abort』來將panic的預設行為從棧展開切換為終止。

接下來我們嘗試一下呼叫panic:

fn main()
報錯資訊:

$ cargo run

compiling panic v0.1.0 (file:///projects/panic)

finished dev [unoptimized + debuginfo] target(s) in 0.25s

running `target/debug/panic`

thread 'main' panicked at 'crash and burn', src/main.rs:2:5

note: run with `rust_backtrace=1` environment variable to display a backtrace.

顯示了我們給的panic資訊,以及panic位置。

略,只是展示了發生錯誤的回溯資訊。

大部分錯誤其實都沒有嚴重到需要整個程式停止執行的地步。例如,嘗試開啟檔案的操作會因為檔案不存在而失敗。你也許會在這種情形下考慮建立新檔案而不是終止程式。

result列舉定義了兩個變體——ok和err,如下所示:

#![allow(unused_variables)]

fn main()

}

這裡的t和e是泛型的引數。t代表了ok變體中包含的值型別,該型別值會在執行成功時返回。e代表了err變體中包含的錯誤型別,該型別值會在執行失敗時返回。

我們現在來開啟乙個檔案,它的返回值將是乙個result,我們需要使用match來處理result

use std::fs::file;

fn main() ", error),

};}

ok表示成功返回file,失敗觸發panic!。

file和error都是臨時定義的變數。

通過=>操作符將變數返回給f。

可以通過match error來確定錯誤型別,進而處理不同型別的錯誤。

use std::fs::file;

use std::io::errorkind;

fn main() ", e),

},other_error => ", other_error)}},

};}

這裡的other_error是新建的臨時變數,可以獲得其餘的錯誤型別。

另外,_佔位符也可以獲得其他錯誤,但是_不是變數,無法在後面使用。

更有經驗的rust開發者可能會像下面這樣實現:

use std::fs::file;

use std::io::errorkind;

fn main() ", error);

})} else ", error);

}});

}

這段**使用了閉包,之後會討論。它沒有使用match,少了很多巢狀,更加易讀。

match處理result很詳盡,但有時太麻煩。可以使用unwrap方法來簡化,在ok時放回ok內部值,在err時呼叫panic!:

use std::fs::file;

fn main()

加入不存在hello.txt檔案,我們執行了這段**,將會報出如下錯誤:

thread 'main' panicked at 'called `result::unwrap()` on an `err` value: error  }',

src/libcore/result.rs:906:4

還有乙個expect方法,它的作用是:它允許我們在unwrap的基礎上指定panic!所附帶的錯誤提示資訊。使用expect並附帶上一段清晰的錯誤提示資訊可以闡明意圖,更容易追蹤到panic:

use std::fs::file;

fn main()

以下是錯誤資訊:

thread 'main' panicked at 'failed to open hello.txt: error  }', src/libcore/result.rs:906:4
有時編寫的函式出現了錯誤,可以把錯誤返回給呼叫者,讓他們決定應該如何做進一步的處理。

我們需要將返回值設定為result,並明確什麼時候返回ok,什麼時候返回err。

#![allow(unused_variables)]

fn main() ;

let mut s = string::new();

match f.read_to_string(&mut s)

}}

_佔位符又出現了,因為這一次不需要再ok裡面宣告變數,所以直接用 _佔位符替代。

#![allow(unused_variables)]

fn main()

}

?運算子可以快速地將錯誤返回。(unwrap是快速處理錯誤,?是快速返回錯誤)

假如這個result的值是ok,那麼包含再ok中的值就會作為這個表示式的結果返回,假如是err,那麼就會返回這個err值。

不過,match表示式和?運算子的乙個區別:

被?運算子所接收的錯誤會被隱式地被from函式處理,這個函式定義與from trait中,用於錯誤型別之間地轉換。當?運算子呼叫from函式時,它就開始嘗試將傳入的錯誤型別轉換為當前函式地返回錯誤型別。當乙個函式擁有不同的失敗原因,卻使用了同一的錯誤返回型別來同事進行表達時,這個功能會十分有用。只要每個錯誤型別都實現了轉換為返回錯誤型別的from函式,?運算子就會自動幫我們處理所有的轉換過程。

?運算子消除了大量模板**,我們甚至可以通過鏈式方法來呼叫進一步簡化**:

#![allow(unused_variables)]

fn main()

}

這個**的作用和之前的**功能一樣,但**量瞬間減少了。

?運算發只能用於返回result的函式或實現了std::ops::try的型別。(因為時返回錯誤的快捷方式啊,不能返回錯誤就沒意義了)

另外,還有一種result:

use std::error::error;

use std::fs::file;

fn main() -> result<(), box>

這裡的box< dyn error >被稱為trait物件,之後討論,你可以簡單理解為「任何可能的錯誤型別」。

只要你能確定自己可以代替呼叫者確定某種情形時不可恢復錯誤,就可以嗲用panic!。

如果你選擇返回result,你就將選擇權交給了呼叫者。

對於某些不太常見的場景,直接觸發panic!要比返回result更合適。

示例新增result導致降低可讀性,因為match**太長了。

原型中往往無法確定錯誤處理方式,只需panic做標記

測試更應該暴露panic,即使這個方法不是需要測試的內容。

當你能明確邏輯上不可能出錯,就放心panic。這裡使用unwrap直接處理。

fn main()
某個錯誤可能會使**處於損壞狀態,這時就使用panic。當某些非法的值,自相矛盾的值,或不存在的值被傳入**,且滿足下列條件時,使用panic:

如果錯誤時可預期的,應該使用result而不是panic。

Swift學習筆記 錯誤處理

錯誤分為可恢復的錯誤和不可恢復的錯誤,可恢復的錯誤指的是能預見並處理的錯誤,例如檔案不存在,網路連線失敗等 不可恢復的錯誤指的是一類特殊的bug,例如強制展開值為nil的可空例項,陣列越界訪問等 如果發生錯誤沒有處理,程式就會停止執行。遺憾的是swift中似乎只能處理可恢復的錯誤。swift中使用a...

python學習筆記 錯誤處理

程式中的錯誤處理有多種方式,一類是約定好錯誤碼,然後根據返回的錯誤碼來判斷是否發生錯誤,以及錯誤的原因。但是這麼做容易將正確的返回值和錯誤碼混在一起,必須要寫很多 來區分,非常不方便。另外一旦出錯,還需要一級一級往上報,知道有一級可以處理它。比較成熟的做法是try.except.finally.這一...

Rust錯誤處理

要不是使用 rust的錯誤處理會顯得有些不夠靈巧。要使用 我們需要宣告返回值型別為result型別,這種型別可以包含任何具備std error error特徵從而可以轉換為bax型別的錯誤型別。拿我們需要處理io錯誤和字串轉換為數字錯誤舉例 use std fs file use std io pr...