欧美free性护士vide0shd,老熟女,一区二区三区,久久久久夜夜夜精品国产,久久久久久综合网天天,欧美成人护士h版

首頁綜合 正文
目錄

柚子快報(bào)邀請(qǐng)碼778899分享:后端 Rust錯(cuò)誤處理

柚子快報(bào)邀請(qǐng)碼778899分享:后端 Rust錯(cuò)誤處理

http://yzkb.51969.com/

文章目錄

返回值和錯(cuò)誤處理panic 深入剖析主動(dòng)調(diào)用backtrace 棧展開panic 時(shí)的兩種終止方式何時(shí)該使用 panic!

返回值和?對(duì)返回的錯(cuò)誤進(jìn)行處理失敗就 panic: unwrap 和 expect傳播錯(cuò)誤? 用于 Option 的返回新手用 ? 常會(huì)犯的錯(cuò)誤帶返回值的 main 函數(shù)

返回值和錯(cuò)誤處理

panic 深入剖析

主動(dòng)調(diào)用

fn main() {

panic!("crash and burn");

}

backtrace 棧展開

panic 時(shí)的兩種終止方式

當(dāng)出現(xiàn) panic! 時(shí),程序提供了兩種方式來處理終止流程:棧展開和直接終止

何時(shí)該使用 panic!

先來一點(diǎn)背景知識(shí),在前面章節(jié)我們粗略講過 Result 這個(gè)枚舉類型,它是用來表示函數(shù)的返回結(jié)果:

enum Result {

Ok(T),

Err(E),

}

當(dāng)沒有錯(cuò)誤發(fā)生時(shí),函數(shù)返回一個(gè)用 Result 類型包裹的值 Ok(T),當(dāng)錯(cuò)誤時(shí),返回一個(gè) Err(E)。對(duì)于 Result 返回我們有很多處理方法,最簡(jiǎn)單粗暴的就是 unwrap 和 expect,這兩個(gè)函數(shù)非常類似,我們以 unwrap 舉例:

use std::net::IpAddr;

let home: IpAddr = "127.0.0.1".parse().unwrap();

返回值和?

對(duì)返回的錯(cuò)誤進(jìn)行處理

use std::fs::File;

use std::io::ErrorKind;

fn main() {

let f = File::open("hello.txt");

let f = match f {

Ok(file) => file,

Err(error) => match error.kind() {

ErrorKind::NotFound => match File::create("hello.txt") {

Ok(fc) => fc,

Err(e) => panic!("Problem creating the file: {:?}", e),

},

other_error => panic!("Problem opening the file: {:?}", other_error),

},

};

}

上面代碼在匹配出 error 后,又對(duì) error 進(jìn)行了詳細(xì)的匹配解析,最終結(jié)果:

如果是文件不存在錯(cuò)誤 ErrorKind::NotFound,就創(chuàng)建文件,這里創(chuàng)建文件File::create 也是返回 Result,因此繼續(xù)用 match 對(duì)其結(jié)果進(jìn)行處理:創(chuàng)建成功,將新的文件句柄賦值給 f,如果失敗,則 panic 剩下的錯(cuò)誤,一律 panicexpect 跟 unwrap 很像,也是遇到錯(cuò)誤直接 panic, 但是會(huì)帶上自定義的錯(cuò)誤提示信息,相當(dāng)于重載了錯(cuò)誤打印的函數(shù):

失敗就 panic: unwrap 和 expect

在不需要處理錯(cuò)誤的場(chǎng)景,例如寫原型、示例時(shí),我們不想使用 match 去匹配 Result 以獲取其中的 T 值,因?yàn)?match 的窮盡匹配特性,你總要去處理下 Err 分支。那么有沒有辦法簡(jiǎn)化這個(gè)過程?有,答案就是 unwrap 和 expect。

use std::fs::File;

fn main() {

let f = File::open("hello.txt").expect("Failed to open hello.txt");

}

如果調(diào)用這段代碼時(shí) hello.txt 文件不存在,那么 unwrap 就將直接 panic:

thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Os { code: 2, kind: NotFound, message: "No such file or directory" }', src/main.rs:4:37

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

expect 跟 unwrap 很像,也是遇到錯(cuò)誤直接 panic, 但是會(huì)帶上自定義的錯(cuò)誤提示信息,相當(dāng)于重載了錯(cuò)誤打印的函數(shù):

use std::fs::File;

fn main() {

let f = File::open("hello.txt").expect("Failed to open hello.txt");

}

報(bào)錯(cuò)如下:

thread 'main' panicked at 'Failed to open hello.txt: Os { code: 2, kind: NotFound, message: "No such file or directory" }', src/main.rs:4:37

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

傳播錯(cuò)誤

程序幾乎不太可能只有 A->B 形式的函數(shù)調(diào)用,一個(gè)設(shè)計(jì)良好的程序,一個(gè)功能涉及十幾層的函數(shù)調(diào)用都有可能。而錯(cuò)誤處理也往往不是哪里調(diào)用出錯(cuò),就在哪里處理,實(shí)際應(yīng)用中,大概率會(huì)把錯(cuò)誤層層上傳然后交給調(diào)用鏈的上游函數(shù)進(jìn)行處理,錯(cuò)誤傳播將極為常見。

例如以下函數(shù)從文件中讀取用戶名,然后將結(jié)果進(jìn)行返回:

use std::fs::File;

use std::io::{self, Read};

fn read_username_from_file() -> Result {

// 打開文件,f是`Result<文件句柄,io::Error>`

let f = File::open("hello.txt");

let mut f = match f {

// 打開文件成功,將file句柄賦值給f

Ok(file) => file,

// 打開文件失敗,將錯(cuò)誤返回(向上傳播)

Err(e) => return Err(e),

};

// 創(chuàng)建動(dòng)態(tài)字符串s

let mut s = String::new();

// 從f文件句柄讀取數(shù)據(jù)并寫入s中

match f.read_to_string(&mut s) {

// 讀取成功,返回Ok封裝的字符串

Ok(_) => Ok(s),

// 將錯(cuò)誤向上傳播

Err(e) => Err(e),

}

}

有幾點(diǎn)值得注意:

該函數(shù)返回一個(gè) Result 類型,當(dāng)讀取用戶名成功時(shí),返回 Ok(String),失敗時(shí),返回 Err(io:Error)File::open 和 f.read_to_string 返回的 Result 中的 E 就是 io::Error 由此可見,該函數(shù)將 io::Error 的錯(cuò)誤往上進(jìn)行傳播,該函數(shù)的調(diào)用者最終會(huì)對(duì) Result 進(jìn)行再處理,至于怎么處理就是調(diào)用者的事,如果是錯(cuò)誤,它可以選擇繼續(xù)向上傳播錯(cuò)誤,也可以直接 panic,亦或?qū)⒕唧w的錯(cuò)誤原因包裝后寫入 socket 中呈現(xiàn)給終端用戶。

傳播界的大明星: ?

use std::fs::File;

use std::io;

use std::io::Read;

fn read_username_from_file() -> Result {

let mut f = File::open("hello.txt")?;

let mut s = String::new();

f.read_to_string(&mut s)?;

Ok(s)

}

看到?jīng)],這就是排面,相比前面的 match 處理錯(cuò)誤的函數(shù),代碼直接減少了一半不止.

其實(shí) ? 就是一個(gè)宏,它的作用跟上面的 match 幾乎一模一樣:

let mut f = match f {

// 打開文件成功,將file句柄賦值給f

Ok(file) => file,

// 打開文件失敗,將錯(cuò)誤返回(向上傳播)

Err(e) => return Err(e),

};

如果結(jié)果是 Ok(T),則把 T 賦值給 f,如果結(jié)果是 Err(E),則返回該錯(cuò)誤,所以 ? 特別適合用來傳播錯(cuò)誤。

雖然 ? 和 match 功能一致,但是事實(shí)上 ? 會(huì)更勝一籌。

想象一下,一個(gè)設(shè)計(jì)良好的系統(tǒng)中,肯定有自定義的錯(cuò)誤特征,錯(cuò)誤之間很可能會(huì)存在上下級(jí)關(guān)系,例如標(biāo)準(zhǔn)庫中的 std::io::Error 和 std::error::Error,前者是 IO 相關(guān)的錯(cuò)誤結(jié)構(gòu)體,后者是一個(gè)最最通用的標(biāo)準(zhǔn)錯(cuò)誤特征,同時(shí)前者實(shí)現(xiàn)了后者,因此 std::io::Error 可以轉(zhuǎn)換為 std:error::Error。

明白了以上的錯(cuò)誤轉(zhuǎn)換,? 的更勝一籌就很好理解了,它可以自動(dòng)進(jìn)行類型提升(轉(zhuǎn)換):

fn open_file() -> Result> {

let mut f = File::open("hello.txt")?;

Ok(f)

}

上面代碼中 File::open 報(bào)錯(cuò)時(shí)返回的錯(cuò)誤是 std::io::Error 類型,但是 open_file 函數(shù)返回的錯(cuò)誤類型是 std::error::Error 的特征對(duì)象,可以看到一個(gè)錯(cuò)誤類型通過 ? 返回后,變成了另一個(gè)錯(cuò)誤類型,這就是 ? 的神奇之處。

根本原因是在于標(biāo)準(zhǔn)庫中定義的 From 特征,該特征有一個(gè)方法 from,用于把一個(gè)類型轉(zhuǎn)成另外一個(gè)類型,? 可以自動(dòng)調(diào)用該方法,然后進(jìn)行隱式類型轉(zhuǎn)換。因此只要函數(shù)返回的錯(cuò)誤 ReturnError 實(shí)現(xiàn)了 From 特征,那么 ? 就會(huì)自動(dòng)把 OtherError 轉(zhuǎn)換為 ReturnError。

這種轉(zhuǎn)換非常好用,意味著你可以用一個(gè)大而全的 ReturnError 來覆蓋所有錯(cuò)誤類型,只需要為各種子錯(cuò)誤類型實(shí)現(xiàn)這種轉(zhuǎn)換即可。

use std::fs::File;

use std::io;

use std::io::Read;

fn read_username_from_file() -> Result {

let mut s = String::new();

File::open("hello.txt")?.read_to_string(&mut s)?;

Ok(s)

}

? ? 還能實(shí)現(xiàn)鏈?zhǔn)秸{(diào)用,F(xiàn)ile::open 遇到錯(cuò)誤就返回,沒有錯(cuò)誤就將 Ok 中的值取出來用于下一個(gè)方法調(diào)用,簡(jiǎn)直太精妙了.

use std::fs;

use std::io;

fn read_username_from_file() -> Result {

// read_to_string是定義在std::io中的方法,因此需要在上面進(jìn)行引用

fs::read_to_string("hello.txt")

}

從文件讀取數(shù)據(jù)到字符串中,是比較常見的操作,因此 Rust 標(biāo)準(zhǔn)庫為我們提供了 fs::read_to_string 函數(shù),該函數(shù)內(nèi)部會(huì)打開一個(gè)文件、創(chuàng)建 String、讀取文件內(nèi)容最后寫入字符串并返回,因?yàn)樵摵瘮?shù)其實(shí)與本章講的內(nèi)容關(guān)系不大,因此放在最后來講,其實(shí)只是我想震你們一下 ?

? 用于 Option 的返回

? 不僅僅可以用于 Result 的傳播,還能用于 Option 的傳播,再來回憶下 Option 的定義:

pub enum Option {

Some(T),

None

}

Result 通過 ? 返回錯(cuò)誤,那么 Option 就通過 ? 返回 None:

fn first(arr: &[i32]) -> Option<&i32> {

let v = arr.get(0)?;

Some(v)

}

新手用 ? 常會(huì)犯的錯(cuò)誤

初學(xué)者在用 ? 時(shí),老是會(huì)犯錯(cuò),例如寫出這樣的代碼:

fn first(arr: &[i32]) -> Option<&i32> {

arr.get(0)?

}

這段代碼無法通過編譯,切記:? 操作符需要一個(gè)變量來承載正確的值,這個(gè)函數(shù)只會(huì)返回 Some(&i32) 或者 None,只有錯(cuò)誤值能直接返回,正確的值不行,所以如果數(shù)組中存在 0 號(hào)元素,那么函數(shù)第二行使用 ? 后的返回類型為 &i32 而不是 Some(&i32)。因此 ? 只能用于以下形式:

let v = xxx()?;

xxx()?.yyy()?;

帶返回值的 main 函數(shù)

在了解了 ? 的使用限制后,這段代碼你很容易看出它無法編譯:

use std::fs::File;

fn main() {

let f = File::open("hello.txt")?;

}

運(yùn)行后會(huì)報(bào)錯(cuò):

$ cargo run

...

the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`)

--> src/main.rs:4:48

|

3 | fn main() {

| --------- this function should return `Result` or `Option` to accept `?`

4 | let greeting_file = File::open("hello.txt")?;

| ^ cannot use the `?` operator in a function that returns `()`

|

= help: the trait `FromResidual>` is not implemented for `()`

因?yàn)?? 要求 Result 形式的返回值,而 main 函數(shù)的返回是 (),因此無法滿足,那是不是就無解了呢?

實(shí)際上 Rust 還支持另外一種形式的 main 函數(shù):

use std::error::Error;

use std::fs::File;

fn main() -> Result<(), Box> {

let f = File::open("hello.txt")?;

Ok(())

}

這樣就能使用 ? 提前返回了,同時(shí)我們又一次看到了Box 特征對(duì)象,因?yàn)?std::error:Error 是 Rust 中抽象層次最高的錯(cuò)誤,其它標(biāo)準(zhǔn)庫中的錯(cuò)誤都實(shí)現(xiàn)了該特征,因此我們可以用該特征對(duì)象代表一切錯(cuò)誤,就算 main 函數(shù)中調(diào)用任何標(biāo)準(zhǔn)庫函數(shù)發(fā)生錯(cuò)誤,都可以通過 Box 這個(gè)特征對(duì)象進(jìn)行返回。

柚子快報(bào)邀請(qǐng)碼778899分享:后端 Rust錯(cuò)誤處理

http://yzkb.51969.com/

參考閱讀

評(píng)論可見,查看隱藏內(nèi)容

本文內(nèi)容根據(jù)網(wǎng)絡(luò)資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點(diǎn)和立場(chǎng)。

轉(zhuǎn)載請(qǐng)注明,如有侵權(quán),聯(lián)系刪除。

本文鏈接:http://gantiao.com.cn/post/19035052.html

發(fā)布評(píng)論

您暫未設(shè)置收款碼

請(qǐng)?jiān)谥黝}配置——文章設(shè)置里上傳

掃描二維碼手機(jī)訪問

文章目錄