最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Rust處理錯(cuò)誤的實(shí)現(xiàn)方法

 更新時(shí)間:2023年03月30日 09:00:08   作者:zy010101  
程序在運(yùn)行的過程中,總是會(huì)不可避免地產(chǎn)生錯(cuò)誤,而如何優(yōu)雅地解決錯(cuò)誤,也是語言的設(shè)計(jì)哲學(xué)之一。本文就來和大家來了Rust是如何處理錯(cuò)誤的,感興趣的可以了解一下

錯(cuò)誤處理

Rust 中的錯(cuò)誤主要分為兩類:

  • 可恢復(fù)錯(cuò)誤,通常用于從系統(tǒng)全局角度來看可以接受的錯(cuò)誤,例如處理用戶的訪問、操作等錯(cuò)誤,這些錯(cuò)誤只會(huì)影響某個(gè)用戶自身的操作進(jìn)程,而不會(huì)對(duì)系統(tǒng)的全局穩(wěn)定性產(chǎn)生影響
  • 不可恢復(fù)錯(cuò)誤,剛好相反,該錯(cuò)誤通常是全局性或者系統(tǒng)性的錯(cuò)誤,例如數(shù)組越界訪問,系統(tǒng)啟動(dòng)時(shí)發(fā)生了影響啟動(dòng)流程的錯(cuò)誤等等,這些錯(cuò)誤的影響往往對(duì)于系統(tǒng)來說是致命的

不可恢復(fù)錯(cuò)誤

不可恢復(fù)錯(cuò)誤通常是非常嚴(yán)重的,例如:程序一開始讀取配置文件失敗或者連接數(shù)據(jù)庫(kù)失敗,諸如此類導(dǎo)致程序運(yùn)行發(fā)生致命錯(cuò)誤的,可以使用不可恢復(fù)錯(cuò)誤。在rust中,觸發(fā)不可恢復(fù)錯(cuò)誤使用panic即可。

觸發(fā)panic可以分為被動(dòng)觸發(fā)和主動(dòng)調(diào)用兩種方式。

被動(dòng)觸發(fā)

下面是一個(gè)被動(dòng)觸發(fā)panic的例子。

fn main() {
    let v = vec![1, 2, 3];
    v[99];
}

這段代碼由于數(shù)組越界訪問,導(dǎo)致被動(dòng)觸發(fā)了panic。錯(cuò)誤信息如下所示:

thread 'main' panicked at 'index out of bounds: the len is 3 but the index is 99', src/main.rs:4:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

backtrace棧展開

可以注意到上面的note提示我們?cè)趓un的時(shí)候使用RUST_BACKTRACE=1來進(jìn)行?;厮荩撕瘮?shù)調(diào)用的順序。例如:

 RUST_BACKTRACE=1 cargo run

執(zhí)行以后輸出的錯(cuò)誤如下所示:

thread 'main' panicked at 'index out of bounds: the len is 3 but the index is 99', src/main.rs:4:5
stack backtrace:
0: rust_begin_unwind
          at /rustc/fc594f15669680fa70d255faec3ca3fb507c3405/library/std/src/panicking.rs:575:5
1: core::panicking::panic_fmt
          at /rustc/fc594f15669680fa70d255faec3ca3fb507c3405/library/core/src/panicking.rs:64:14
2: core::panicking::panic_bounds_check
          at /rustc/fc594f15669680fa70d255faec3ca3fb507c3405/library/core/src/panicking.rs:147:5
3: <usize as core::slice::index::SliceIndex<[T]>>::index
          at /rustc/fc594f15669680fa70d255faec3ca3fb507c3405/library/core/src/slice/index.rs:260:10
4: core::slice::index::<impl core::ops::index::Index<I> for [T]>::index
          at /rustc/fc594f15669680fa70d255faec3ca3fb507c3405/library/core/src/slice/index.rs:18:9
5: <alloc::vec::Vec<T,A> as core::ops::index::Index<I>>::index
          at /rustc/fc594f15669680fa70d255faec3ca3fb507c3405/library/alloc/src/vec/mod.rs:2727:9
6: error_handling::main
          at ./src/main.rs:4:5
7: core::ops::function::FnOnce::call_once
          at /rustc/fc594f15669680fa70d255faec3ca3fb507c3405/library/core/src/ops/function.rs:507:5
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.

最近調(diào)用的函數(shù)排在列表的最上方。因?yàn)樵蹅兊?main 函數(shù)基本是最先調(diào)用的函數(shù)了,所以排在了倒數(shù)第二位,還有一個(gè)關(guān)注點(diǎn),排在最頂部最后一個(gè)調(diào)用的函數(shù)是 rust_begin_unwind,該函數(shù)的目的就是進(jìn)行棧展開,呈現(xiàn)這些列表信息給我們。

要獲取到?;厮菪畔?,你還需要開啟 debug 標(biāo)志,該標(biāo)志在使用 cargo run 或者 cargo build 時(shí)自動(dòng)開啟(這兩個(gè)操作默認(rèn)是 Debug 運(yùn)行方式)。同時(shí),棧展開信息在不同操作系統(tǒng)或者 Rust 版本上也有所不同。

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

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

其中,默認(rèn)的方式就是 棧展開,這意味著 Rust 會(huì)回溯棧上數(shù)據(jù)和函數(shù)調(diào)用,因此也意味著更多的善后工作,好處是可以給出充分的報(bào)錯(cuò)信息和棧調(diào)用信息,便于事后的問題復(fù)盤。直接終止,顧名思義,不清理數(shù)據(jù)就直接退出程序,善后工作交與操作系統(tǒng)來負(fù)責(zé)。

對(duì)于絕大多數(shù)用戶,使用默認(rèn)選擇是最好的,但是當(dāng)你關(guān)心最終編譯出的二進(jìn)制可執(zhí)行文件大小時(shí),那么可以嘗試去使用直接終止的方式,例如下面的配置修改 Cargo.toml 文件,實(shí)現(xiàn)在 release 模式下遇到 panic 直接終止:

[profile.release]
panic = 'abort'

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

在某些特殊場(chǎng)景中,開發(fā)者想要主動(dòng)拋出一個(gè)異常。rust提供了panic!宏,它可以在你調(diào)用時(shí),打印出一個(gè)錯(cuò)誤信息,展開報(bào)錯(cuò)點(diǎn)往前的函數(shù)調(diào)用堆棧,最后退出程序。一定是不可恢復(fù)的錯(cuò)誤,才調(diào)用 panic! 處理,你總不想系統(tǒng)僅僅因?yàn)橛脩綦S便傳入一個(gè)非法參數(shù)就崩潰吧?所以,只有當(dāng)你不知道該如何處理時(shí),再去調(diào)用 panic!

fn main() {
    panic!("crash");
}

運(yùn)行后輸出:

thread 'main' panicked at 'crash', src/main.rs:8:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

它告訴我們,main 函數(shù)所在的線程崩潰了,發(fā)生的代碼位置是 src/main.rs 中的第 8 行第 5 個(gè)字符(去除該行前面的空字符)

線程panic后程序是否會(huì)終止

如果是 main 線程,則程序會(huì)終止,如果是其它子線程,該線程會(huì)終止,但是不會(huì)影響 main 線程。因此,盡量不要在 main 線程中做太多任務(wù),將這些任務(wù)交由子線程去做,就算子線程 panic 也不會(huì)導(dǎo)致整個(gè)程序的結(jié)束。

Result枚舉類型

它被定義為如下:

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

泛型參數(shù) T 代表成功時(shí)存入的正確值的類型,存放方式是 Ok(T),E 代表錯(cuò)誤時(shí)存入的錯(cuò)誤值,存放方式是 Err(E)。一個(gè)實(shí)際的例子如下:

#![allow(unused)]
use std::fs::File;
fn main() {
    let f = File::open("hello.txt");
    let f = match f {
        Ok(file) => file,
        Err(error) => {
            panic!("Problem opening the file: {:?}", error)
        },
    };
}

代碼很清晰,對(duì)打開文件后的 Result<T, E> 類型進(jìn)行匹配取值,如果是成功,則將 Ok(file) 中存放的的文件句柄 file 賦值給 f,如果失敗,則將 Err(error) 中存放的錯(cuò)誤信息 error 使用 panic 拋出來,進(jìn)而結(jié)束程序。

直接 panic 還是過于粗暴,因?yàn)閷?shí)際上 IO 的錯(cuò)誤有很多種,我們需要對(duì)部分錯(cuò)誤進(jìn)行特殊處理,而不是所有錯(cuò)誤都直接崩潰:

#![allow(unused)]
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ò)誤,一律 panic.

unwrap和expect

它們的作用就是,如果返回成功,就將 Ok(T) 中的值取出來,如果失敗,就直接 panic。例如:

use std::fs::File;
fn main() {
    let f = File::open("hello.txt").unwrap();
}

如果hello.txt不存在,則會(huì)導(dǎo)致panic;而expect會(huì)帶上自定義的錯(cuò)誤提示信息,相當(dāng)于重載了錯(cuò)誤打印的函數(shù):

use std::fs::File;
fn main() {
    let f = File::open("hello.txt").expect("Failed to open hello.txt");
}

如果hello.txt不存在,那么panic的時(shí)候expect會(huì)帶上自定義的錯(cuò)誤提示信息“Failed to open hello.txt”。

傳播錯(cuò)誤

rust提供了錯(cuò)誤傳遞的方式,以滿足不同的編程風(fēng)格來處理錯(cuò)誤。有的人喜歡原地處理,有的人則是需要將錯(cuò)誤傳遞到上層調(diào)用處進(jìn)行處理。rust提供了?來進(jìn)行錯(cuò)誤傳播。例如:

#![allow(unused)]
fn main() {
use std::fs::File;
use std::io;
use std::io::Read;
fn read_username_from_file() -> Result<String, io::Error> {
    let mut f = File::open("hello.txt")?;
    let mut s = String::new();
    f.read_to_string(&mut s)?;
    Ok(s)
}
let res = read_username_from_file();
dbg!(&res);
}

我們?cè)诖颂庍M(jìn)行了錯(cuò)誤傳遞,當(dāng)前目錄下不存在hello.txt是,?會(huì)把發(fā)生的錯(cuò)誤傳遞到上層,也是就是調(diào)用read_username_from_file處,錯(cuò)誤結(jié)果保存在res中。輸出如下所示:

[src/main.rs:64] &res = Err(
    Os {
        code: 2,
        kind: NotFound,
        message: "No such file or directory",
    },
)

詳細(xì)的顯示了錯(cuò)誤信息,包含錯(cuò)誤碼code,錯(cuò)誤種類kind,錯(cuò)誤消息message。?其實(shí)是一個(gè)宏。當(dāng)使用 ? 運(yùn)算符時(shí),如果表達(dá)式的結(jié)果是一個(gè)錯(cuò)誤值,那么整個(gè)函數(shù)將立即返回這個(gè)錯(cuò)誤值,否則會(huì)將表達(dá)式的結(jié)果進(jìn)行包裝并繼續(xù)執(zhí)行函數(shù)。?的強(qiáng)大之處在于自動(dòng)類型提升,例如:

fn main() {
fn open_file() -> Result<File, Box<dyn std::error::Error>> {
    let mut f = File::open("hello.txt")?;
    Ok(f)
}
let res = open_file();
dbg!(&res);
}

當(dāng)前目錄下沒有hello.txt時(shí),open會(huì)失敗,此時(shí)發(fā)送的錯(cuò)誤是std::io::Error 類型,但是 open_file 函數(shù)返回的錯(cuò)誤類型是 std::error::Error 的特征對(duì)象。標(biāo)準(zhǔn)庫(kù)中定義的 From 特征,該特征有一個(gè)方法 from,用于把一個(gè)類型轉(zhuǎn)成另外一個(gè)類型,? 可以自動(dòng)調(diào)用該方法,然后進(jìn)行隱式類型轉(zhuǎn)換。因此只要函數(shù)返回的錯(cuò)誤 ReturnError 實(shí)現(xiàn)了 From<OtherError> 特征,那么 ? 就會(huì)自動(dòng)把 OtherError 轉(zhuǎn)換為 ReturnError。除此之外,?還可以實(shí)現(xiàn)鏈?zhǔn)秸{(diào)用。例如:

#![allow(unused)]
fn main() {
use std::fs::File;
use std::io;
use std::io::Read;
fn read_username_from_file() -> Result<String, io::Error> {
    let mut s = String::new();
    File::open("hello.txt")?.read_to_string(&mut s)?;
    Ok(s)
}
}

確實(shí)牛逼,這樣就不用寫一大堆代碼來處理錯(cuò)誤了。

?用于Option返回

? 不僅僅可以用于 Result 的傳播,還能用于 Option 的傳播。

fn main() {
fn last_char_of_first_line(text: &str) -> Option<char> {
    text.lines().next()?.chars().last()
}
let res = last_char_of_first_line("123");
dbg!(&res);
}

如果next返回的是None,那么執(zhí)行結(jié)束,直接返回None,否則接著進(jìn)行鏈?zhǔn)秸{(diào)用。

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

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

use std::fs::File;
fn main() {
    let f = File::open("hello.txt")?;
}

因?yàn)?? 要求 Result<T, E> 形式的返回值,而 main 函數(shù)的返回是 (),怎么辦?實(shí)際上 Rust 還支持另外一種形式的 main 函數(shù):

use std::error::Error;
use std::fs::File;
fn main() -> Result<(), Box<dyn Error>> {
    let f = File::open("hello.txt")?;
    Ok(())
}

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

到此這篇關(guān)于Rust處理錯(cuò)誤的實(shí)現(xiàn)方法的文章就介紹到這了,更多相關(guān)Rust處理錯(cuò)誤內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • rust引用和借用的使用小結(jié)

    rust引用和借用的使用小結(jié)

    在rust中,引用的語法非常簡(jiǎn)單。通過&來取引用,通過*來解引用,這篇文章主要介紹了rust引用和借用的使用小結(jié),總的來說,借用規(guī)則,同一時(shí)刻,你只能擁有要么一個(gè)可變引用,?要么任意多個(gè)不可變引用,具體內(nèi)容詳情跟隨小編一起看看吧
    2023-01-01
  • Rust初體驗(yàn):手把手教你構(gòu)建‘Hello,?World!’

    Rust初體驗(yàn):手把手教你構(gòu)建‘Hello,?World!’

    "準(zhǔn)備好了嗎?一起踏上Rust編程語言的精彩旅程!在這篇「Rust初體驗(yàn)」中,我們將手把手教你構(gòu)建經(jīng)典程序“Hello,?World!”,感受Rust的強(qiáng)大與安全,短短幾行代碼,就能讓你對(duì)這個(gè)系統(tǒng)級(jí)語言的魅力一探究竟!快加入吧,驚喜等你發(fā)現(xiàn)!"
    2024-01-01
  • rust 中的 EBNF簡(jiǎn)介舉例

    rust 中的 EBNF簡(jiǎn)介舉例

    這篇文章主要介紹了rust 中的 EBNF簡(jiǎn)介舉例,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2025-05-05
  • Rust安裝的圖文教程

    Rust安裝的圖文教程

    本文主要介紹了Rust安裝的圖文教程,文中通過圖文示例介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2025-06-06
  • Rust 中判斷兩個(gè) HashMap 是否相等

    Rust 中判斷兩個(gè) HashMap 是否相等

    在Rust標(biāo)準(zhǔn)庫(kù)中,HashMap 實(shí)現(xiàn)了 PartialEq 和 Eq trait,但是這些trait的實(shí)現(xiàn)是基于嚴(yán)格的結(jié)構(gòu)相等性,包括元素的順序,這篇文章主要介紹了Rust 中判斷兩個(gè) HashMap 是否相等,需要的朋友可以參考下
    2024-04-04
  • 使用Rust語言編寫一個(gè)ChatGPT桌面應(yīng)用示例詳解

    使用Rust語言編寫一個(gè)ChatGPT桌面應(yīng)用示例詳解

    這篇文章主要介紹了如何用Rust編寫一個(gè)ChatGPT桌面應(yīng)用,文中有詳細(xì)的流程介紹,對(duì)大家的學(xué)習(xí)或工作有意一定的幫助,需要的朋友可以參考下
    2023-05-05
  • Rust生命周期常見誤區(qū)(中英對(duì)照)全面指南

    Rust生命周期常見誤區(qū)(中英對(duì)照)全面指南

    這篇文章主要WEIDJAI?介紹了Rust生命周期常見誤區(qū)(中英對(duì)照)的全面指南,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-11-11
  • Rust 智能指針的使用詳解

    Rust 智能指針的使用詳解

    Rust智能指針是內(nèi)存管理核心工具,本文就來詳細(xì)的介紹一下Rust智能指針(Box、Rc、RefCell、Arc、Mutex、RwLock、Weak)的原理與使用場(chǎng)景,感興趣的可以了解一下
    2025-09-09
  • Rust CLI 項(xiàng)目構(gòu)建的實(shí)現(xiàn)步驟

    Rust CLI 項(xiàng)目構(gòu)建的實(shí)現(xiàn)步驟

    本文提供了一個(gè)完整的Rust CLI項(xiàng)目構(gòu)建流程,以 anthropic-config 配置管理工具為例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2025-12-12
  • 一步到位,教你如何在Windows成功安裝Rust

    一步到位,教你如何在Windows成功安裝Rust

    一步到位:輕松學(xué)會(huì)在Windows上安裝Rust!想快速掌握Rust編程語言?別再為復(fù)雜教程頭疼!這份指南將手把手帶你順利完成Windows平臺(tái)上的Rust安裝全過程,從此編碼之旅更加順暢無阻,立即閱讀,開始你的Rust編程旅程吧!
    2024-01-01

最新評(píng)論

同德县| 沾化县| 滦南县| 龙岩市| 龙游县| 华池县| 兖州市| 楚雄市| 香河县| 大邑县| 岑溪市| 庄浪县| 岫岩| 龙泉市| 普格县| 东台市| 灵丘县| 西青区| 恩施市| 洪洞县| 靖宇县| 蒙阴县| 西乌| 禄丰县| 濮阳县| 安新县| 沈阳市| 沿河| 保靖县| 车致| 兴城市| 周口市| 乌鲁木齐县| 孝感市| 安岳县| 日喀则市| 柘城县| 阳谷县| 栾川县| 临颍县| 东港市|