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

探索?Rust?中實(shí)用的錯(cuò)誤處理技巧

 更新時(shí)間:2024年01月25日 08:22:05   作者:和你一起去月球  
探索Rust中實(shí)用的錯(cuò)誤處理技巧!Rust是一門靜態(tài)類型系統(tǒng)安全且高效的編程語(yǔ)言,但使用過(guò)程中難免會(huì)遇到各種錯(cuò)誤,學(xué)會(huì)如何正確處理這些錯(cuò)誤至關(guān)重要,本指南將為您提供一些實(shí)用的錯(cuò)誤處理技巧,幫助您更好地編寫(xiě)健壯的代碼,需要的朋友可以參考下

錯(cuò)誤是軟件中不可否認(rèn)的事實(shí),所以 Rust 有一些處理出錯(cuò)情況的特性。在許多情況下,Rust 要求你承認(rèn)錯(cuò)誤的可能性,并在你的代碼編譯前采取一些行動(dòng)。這一要求使你的程序更加健壯,因?yàn)樗梢源_保你在將代碼部署到生產(chǎn)環(huán)境之前就能發(fā)現(xiàn)錯(cuò)誤并進(jìn)行適當(dāng)?shù)奶幚怼?/p>

Rust 將錯(cuò)誤分為兩大類:可恢復(fù)的(recoverable)和 不可恢復(fù)的(unrecoverable)錯(cuò)誤。對(duì)于一個(gè)可恢復(fù)的錯(cuò)誤,比如文件未找到的錯(cuò)誤,我們很可能只想向用戶報(bào)告問(wèn)題并重試操作。不可恢復(fù)的錯(cuò)誤總是 bug 出現(xiàn)的征兆,比如試圖訪問(wèn)一個(gè)超過(guò)數(shù)組末端的位置,因此我們要立即停止程序。

大多數(shù)語(yǔ)言并不區(qū)分這兩種錯(cuò)誤,并采用類似異常這樣方式統(tǒng)一處理它們。Rust 沒(méi)有異常。相反,它有 Result<T, E> 類型,用于處理可恢復(fù)的錯(cuò)誤,還有 panic! 宏,在程序遇到不可恢復(fù)的錯(cuò)誤時(shí)停止執(zhí)行。本章首先介紹 panic! 調(diào)用,接著會(huì)講到如何返回 Result<T, E>。此外,我們將探討在決定是嘗試從錯(cuò)誤中恢復(fù)還是停止執(zhí)行時(shí)的注意事項(xiàng)。

1、用 panic! 處理不可恢復(fù)的錯(cuò)誤

突然有一天,代碼出問(wèn)題了,而你對(duì)此束手無(wú)策。對(duì)于這種情況,Rust 有 panic!宏。在實(shí)踐中有兩種方法造成 panic:執(zhí)行會(huì)造成代碼 panic 的操作(比如訪問(wèn)超過(guò)數(shù)組結(jié)尾的內(nèi)容)或者顯式調(diào)用 panic! 宏。這兩種情況都會(huì)使程序 panic。通常情況下這些 panic 會(huì)打印出一個(gè)錯(cuò)誤信息,展開(kāi)并清理?xiàng)?shù)據(jù),然后退出。通過(guò)一個(gè)環(huán)境變量,你也可以讓 Rust 在 panic 發(fā)生時(shí)打印調(diào)用堆棧(call stack)以便于定位 panic 的原因。

對(duì)應(yīng) panic 時(shí)的棧展開(kāi)或終止

當(dāng)出現(xiàn) panic 時(shí),程序默認(rèn)會(huì)開(kāi)始 展開(kāi)(unwinding),這意味著 Rust 會(huì)回溯棧并清理它遇到的每一個(gè)函數(shù)的數(shù)據(jù),不過(guò)這個(gè)回溯并清理的過(guò)程有很多工作。另一種選擇是直接 終止(abort),這會(huì)不清理數(shù)據(jù)就退出程序。

那么程序所使用的內(nèi)存需要由操作系統(tǒng)來(lái)清理。如果你需要項(xiàng)目的最終二進(jìn)制文件越小越好,panic 時(shí)通過(guò)在 Cargo.toml 的 [profile] 部分增加 panic = 'abort',可以由展開(kāi)切換為終止。例如,如果你想要在 release 模式中 panic 時(shí)直接終止:

[profile.release] panic = 'abort'

我們可以再程序中主動(dòng)拋出一個(gè)錯(cuò)誤,如下圖所示:

fn main() {
    panic!("error error error ...")
}

 運(yùn)行一下程序,會(huì)打印如下信息:

通過(guò)上圖可以知道:

第一行顯示的是程序代碼發(fā)生錯(cuò)誤的位置,main.rs 的第二行第五列開(kāi)始的。

第二行顯示的是panic!里面,我們自定義的錯(cuò)誤內(nèi)容。

第三行告訴我們可以使用 panic! 被調(diào)用的函數(shù)的 backtrace 來(lái)尋找代碼中出問(wèn)題的地方。

1.1 使用 panic! 的 backtrace

讓我們來(lái)看看另一個(gè)因?yàn)槲覀兇a中的 bug 引起的別的庫(kù)中 panic! 的例子,而不是直接的宏調(diào)用。示例如下所示:

fn main() {
    let arr = [10, 20, 30, 40, 50];
    arr[100];
}

這里嘗試訪問(wèn) vector 的第一百個(gè)元素(這里的索引是 99 因?yàn)樗饕龔?0 開(kāi)始),不過(guò)它只有三個(gè)元素。這種情況下 Rust 會(huì) panic。[] 應(yīng)當(dāng)返回一個(gè)元素,不過(guò)如果傳遞了一個(gè)無(wú)效索引,就沒(méi)有可供 Rust 返回的正確的元素。

C 語(yǔ)言中,嘗試讀取數(shù)據(jù)結(jié)構(gòu)之后的值是未定義行為(undefined behavior)。你會(huì)得到任何對(duì)應(yīng)數(shù)據(jù)結(jié)構(gòu)中這個(gè)元素的內(nèi)存位置的值,甚至是這些內(nèi)存并不屬于這個(gè)數(shù)據(jù)結(jié)構(gòu)的情況。這被稱為 緩沖區(qū)溢出(buffer overread),并可能會(huì)導(dǎo)致安全漏洞,比如攻擊者可以像這樣操作索引來(lái)讀取儲(chǔ)存在數(shù)據(jù)結(jié)構(gòu)之后不被允許的數(shù)據(jù)。

為了保護(hù)程序遠(yuǎn)離這類漏洞,如果嘗試讀取一個(gè)索引不存在的元素,Rust 會(huì)停止執(zhí)行并拒絕繼續(xù)。嘗試運(yùn)行上面的程序會(huì)出現(xiàn)如下:

報(bào)錯(cuò):運(yùn)行時(shí)遇到panic錯(cuò)誤,在main.rs第三行第五列開(kāi)始,索引超過(guò)邊界,長(zhǎng)度為5,而索引值確實(shí)100。

讓我們將 RUST_BACKTRACE 環(huán)境變量設(shè)置為1 的值來(lái)獲取 backtrace 看看。

這是數(shù)組,報(bào)錯(cuò)比較簡(jiǎn)單,如果其他數(shù)據(jù)結(jié)構(gòu)我們可以看一下結(jié)果,例如:string

fn main() {
    let arr = String::from("hello");
    arr[100];
}

 打印結(jié)果如下所示:

這里有大量的輸出!你實(shí)際看到的輸出可能因不同的操作系統(tǒng)和 Rust 版本而有所不同。為了獲取帶有這些信息的 backtrace,必須啟用 debug 標(biāo)識(shí)。當(dāng)不使用 --release 參數(shù)運(yùn)行 cargo build 或 cargo run 時(shí) debug 標(biāo)識(shí)會(huì)默認(rèn)啟用,就像這里一樣。

在上圖中,我們可以看到報(bào)錯(cuò)具體的文件以及對(duì)應(yīng)的行號(hào),下面還有rust程序報(bào)錯(cuò)更加詳細(xì)的原因,這樣可以更快的為我們解決問(wèn)題,提升自己的效率。

2、用 Result 處理可恢復(fù)的錯(cuò)誤

大部分錯(cuò)誤并沒(méi)有嚴(yán)重到需要程序完全停止執(zhí)行。有時(shí)候,一個(gè)函數(shù)失敗,僅僅就是因?yàn)橐粋€(gè)容易理解和響應(yīng)的原因。例如,如果因?yàn)榇蜷_(kāi)一個(gè)并不存在的文件而失敗,此時(shí)我們可能想要?jiǎng)?chuàng)建這個(gè)文件,而不是終止進(jìn)程。

Result 枚舉,它定義有如下兩個(gè)成員,Ok 和 Err

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

T 和 E 是泛型類型參數(shù);現(xiàn)在你需要知道的就是 T 代表成功時(shí)返回的 Ok 成員中的數(shù)據(jù)的類型,而 E 代表失敗時(shí)返回的 Err 成員中的錯(cuò)誤的類型。因?yàn)?nbsp;Result 有這些泛型類型參數(shù),我們可以將 Result 類型和標(biāo)準(zhǔn)庫(kù)中為其定義的函數(shù)用于很多不同的場(chǎng)景,這些情況中需要返回的成功值和失敗值可能會(huì)各不相同。

讓我們調(diào)用一個(gè)返回 Result 的函數(shù),因?yàn)樗赡軙?huì)失?。嚎匆幌氯缦率纠?/p>

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

File::open 的返回值是 Result<T, E>。泛型參數(shù) T 會(huì)被 File::open 的實(shí)現(xiàn)放入成功返回值的類型 std::fs::File,這是一個(gè)文件句柄。錯(cuò)誤返回值使用的 E 的類型是 std::io::Error。這些返回類型意味著 File::open 調(diào)用可能成功并返回一個(gè)可以讀寫(xiě)的文件句柄。這個(gè)函數(shù)調(diào)用也可能會(huì)失?。豪?,也許文件不存在,或者可能沒(méi)有權(quán)限訪問(wèn)這個(gè)文件。File::open 函數(shù)需要一個(gè)方法在告訴我們成功與否的同時(shí)返回文件句柄或者錯(cuò)誤信息。這些信息正好是 Result 枚舉所代表的。

當(dāng) File::open 成功時(shí),greeting_file_result 變量將會(huì)是一個(gè)包含文件句柄的 Ok 實(shí)例。當(dāng)失敗時(shí),greeting_file_result 變量將會(huì)是一個(gè)包含了更多關(guān)于發(fā)生了何種錯(cuò)誤的信息的 Err 實(shí)例。

這里使用match表達(dá)式來(lái)處理結(jié)果:

 
fn main() {
    let file_result = File::open("hello.txt");
    let res = match file_result {
        Ok(file) => file,
        Err(err) => panic!("打開(kāi)文件發(fā)生錯(cuò)誤...{:?}", err),
    };
}

當(dāng)我們運(yùn)行以上代碼時(shí),看一下輸出結(jié)果如何:

2.1 匹配不同的錯(cuò)誤 

上面的代碼不管 File::open 是因?yàn)槭裁丛蚴《紩?huì) panic!。我們真正希望的是對(duì)不同的錯(cuò)誤原因采取不同的行為:如果 File::open 因?yàn)槲募淮嬖诙?,我們希望?chuàng)建這個(gè)文件并返回新文件的句柄。如果 File::open 因?yàn)槿魏纹渌蚴?,例如沒(méi)有打開(kāi)文件的權(quán)限,我們可以通過(guò)不同分支把錯(cuò)誤提示的更加詳細(xì)。

fn main() {
    let file_result = File::open("hello.txt");
    match file_result {
        Ok(file) => file,
        Err(err) => match err.kind() {
            ErrorKind::NotFound => match File::create("hello.txt") {
                Ok(file) => file,
                Err(err) => panic!("創(chuàng)建文件失敗 {:?}", err),
            },
            other_error => panic!("其他錯(cuò)誤 {:?}", other_error),
        },
    };
}

File::open 返回的 Err 成員中的值類型 io::Error,它是一個(gè)標(biāo)準(zhǔn)庫(kù)中提供的結(jié)構(gòu)體。這個(gè)結(jié)構(gòu)體有一個(gè)返回 io::ErrorKind 值的 kind 方法可供調(diào)用。io::ErrorKind 是一個(gè)標(biāo)準(zhǔn)庫(kù)提供的枚舉,它的成員對(duì)應(yīng) io 操作可能導(dǎo)致的不同錯(cuò)誤類型。我們感興趣的成員是 ErrorKind::NotFound,它代表嘗試打開(kāi)的文件并不存在。這樣,match 就匹配完 greeting_file_result 了,不過(guò)對(duì)于 error.kind() 還有一個(gè)內(nèi)層 match。

我們希望在內(nèi)層 match 中檢查的條件是 error.kind() 的返回值是否為 ErrorKind的 NotFound 成員。如果是,則嘗試通過(guò) File::create 創(chuàng)建文件。然而因?yàn)?nbsp;File::create 也可能會(huì)失敗,還需要增加一個(gè)內(nèi)層 match 語(yǔ)句。當(dāng)文件不能被打開(kāi),會(huì)打印出一個(gè)不同的錯(cuò)誤信息。外層 match 的最后一個(gè)分支保持不變,這樣對(duì)任何除了文件不存在的錯(cuò)誤會(huì)使程序 panic。

2.2 失敗時(shí) panic 的簡(jiǎn)寫(xiě):unwrap 和 expect

match 能夠勝任它的工作,不過(guò)它可能有點(diǎn)冗長(zhǎng)并且不總是能很好的表明其意圖。Result<T, E> 類型定義了很多輔助方法來(lái)處理各種情況。其中之一叫做 unwrap,它的實(shí)現(xiàn)就像上個(gè)示例中的 match 語(yǔ)句。如果 Result 值是成員 Okunwrap 會(huì)返回 Ok 中的值。如果 Result 是成員 Err,unwrap 會(huì)為我們調(diào)用 panic!。這里是一個(gè)實(shí)踐 unwrap 的例子:

fn main() {
    let file_result = File::open("hello.txt").unwrap();
}

運(yùn)行一下這個(gè)程序,看下對(duì)應(yīng)的輸出:

還有另一個(gè)類似于 unwrap 的方法它還允許我們選擇 panic! 的錯(cuò)誤信息:expect。使用 expect 而不是 unwrap 并提供一個(gè)好的錯(cuò)誤信息可以表明你的意圖并更易于追蹤 panic 的根源。expect 的語(yǔ)法看起來(lái)像這樣:

fn main() {
    let file_result = File::open("hello.txt").expect("沒(méi)有讀取到文件");
}

expect 與 unwrap 的使用方式一樣:返回文件句柄或調(diào)用 panic! 宏。expect 在調(diào)用 panic! 時(shí)使用的錯(cuò)誤信息將是我們傳遞給 expect 的參數(shù),而不像 unwrap 那樣使用默認(rèn)的 panic! 信息。它看起來(lái)像這樣:

在生產(chǎn)級(jí)別的代碼中,大部分 Rustaceans 選擇 expect 而不是 unwrap 并提供更多關(guān)于為何操作期望是一直成功的上下文。

2.3 傳播錯(cuò)誤

當(dāng)編寫(xiě)一個(gè)其實(shí)先會(huì)調(diào)用一些可能會(huì)失敗的操作的函數(shù)時(shí),除了在這個(gè)函數(shù)中處理錯(cuò)誤外,還可以選擇讓調(diào)用者知道這個(gè)錯(cuò)誤并決定該如何處理。這被稱為 傳播(propagating)錯(cuò)誤,這樣能更好的控制代碼調(diào)用,因?yàn)楸绕鹉愦a所擁有的上下文,調(diào)用者可能擁有更多信息或邏輯來(lái)決定應(yīng)該如何處理錯(cuò)誤。

例如,示例 9-6 展示了一個(gè)從文件中讀取用戶名的函數(shù)。如果文件不存在或不能讀取,這個(gè)函數(shù)會(huì)將這些錯(cuò)誤返回給調(diào)用它的代碼:

fn main() {
    fn read_file() -> Result<String, io::Error> {
        let file_result = File::open("hello.txt");
        let v = String::from("open file success ...");
        match file_result {
            Ok(_) => Ok(v),
            Err(err) => Err(err),
        }
    }
    let res = read_file();
    print!("{:?}", res)
}

這個(gè)函數(shù)可以編寫(xiě)成更加簡(jiǎn)短的形式,不過(guò)我們以大量手動(dòng)處理開(kāi)始以便探索錯(cuò)誤處理;在最后我們會(huì)展示更短的形式。讓我們看看函數(shù)的返回值:Result<String, io::Error>。這意味著函數(shù)返回一個(gè) Result<T, E> 類型的值,其中泛型參數(shù) T 的具體類型是 String,而 E 的具體類型是 io::Error。

如果這個(gè)函數(shù)沒(méi)有出任何錯(cuò)誤成功返回,函數(shù)的調(diào)用者會(huì)收到一個(gè)包含 String 的 Ok 值 —— 函數(shù)從文件中讀取到的用戶名。如果函數(shù)遇到任何錯(cuò)誤,函數(shù)的調(diào)用者會(huì)收到一個(gè) Err 值,它儲(chǔ)存了一個(gè)包含更多這個(gè)問(wèn)題相關(guān)信息的 io::Error 實(shí)例。

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

相關(guān)文章

  • 使用Rust制作康威生命游戲的實(shí)現(xiàn)代碼

    使用Rust制作康威生命游戲的實(shí)現(xiàn)代碼

    這篇文章主要介紹了使用Rust制作康威生命游戲,初始rust項(xiàng)目,使用wasm的項(xiàng)目模板,結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-09-09
  • rust引用和借用的使用小結(jié)

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

    在rust中,引用的語(yǔ)法非常簡(jiǎn)單。通過(guò)&來(lái)取引用,通過(guò)*來(lái)解引用,這篇文章主要介紹了rust引用和借用的使用小結(jié),總的來(lái)說(shuō),借用規(guī)則,同一時(shí)刻,你只能擁有要么一個(gè)可變引用,?要么任意多個(gè)不可變引用,具體內(nèi)容詳情跟隨小編一起看看吧
    2023-01-01
  • 用rust?寫(xiě)一個(gè)jar包?class沖突檢測(cè)工具

    用rust?寫(xiě)一個(gè)jar包?class沖突檢測(cè)工具

    這篇文章主要介紹了用rust?寫(xiě)一個(gè)jar包?class沖突檢測(cè)工具?的相關(guān)資料,需要的朋友可以參考下
    2023-05-05
  • Rust之模式與模式匹配的實(shí)現(xiàn)

    Rust之模式與模式匹配的實(shí)現(xiàn)

    Rust中的模式匹配功能強(qiáng)大且靈活,它極大地提高了代碼的表達(dá)力和可讀性,本文主要介紹了Rust之模式與模式匹配,具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-03-03
  • RUST語(yǔ)言函數(shù)的定義與調(diào)用方法

    RUST語(yǔ)言函數(shù)的定義與調(diào)用方法

    定義一個(gè)RUST函數(shù)使用fn關(guān)鍵字,下面通過(guò)本文給大家介紹RUST語(yǔ)言函數(shù)的定義與調(diào)用方法,感興趣的朋友跟隨小編一起看看吧
    2024-04-04
  • Rust中箱、包和模塊的學(xué)習(xí)筆記

    Rust中箱、包和模塊的學(xué)習(xí)筆記

    Rust中有三個(gè)重要的組織概念:箱、包、模塊,本文主要介紹了Rust中箱、包和模塊的學(xué)習(xí)筆記,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2024-03-03
  • Rust異步Web框架Axum的深入原理解析與高級(jí)用法

    Rust異步Web框架Axum的深入原理解析與高級(jí)用法

    Axum是一個(gè)功能強(qiáng)大、簡(jiǎn)單易用的異步Web框架,基于Tokio異步運(yùn)行時(shí),具有高度模塊化的架構(gòu)和類型安全的特點(diǎn),通過(guò)本文的介紹,我們學(xué)習(xí)了Axum框架的架構(gòu)與核心組件、路由系統(tǒng)、高級(jí)功能、性能優(yōu)化方法、實(shí)戰(zhàn)項(xiàng)目的應(yīng)用以及常見(jiàn)問(wèn)題的解決方案
    2026-03-03
  • Rust中類型轉(zhuǎn)換在錯(cuò)誤處理中的應(yīng)用小結(jié)

    Rust中類型轉(zhuǎn)換在錯(cuò)誤處理中的應(yīng)用小結(jié)

    隨著項(xiàng)目的進(jìn)展,關(guān)于Rust的故事又翻開(kāi)了新的一頁(yè),今天來(lái)到了服務(wù)器端的開(kāi)發(fā)場(chǎng)景,發(fā)現(xiàn)錯(cuò)誤處理中的錯(cuò)誤類型轉(zhuǎn)換有必要分享一下,對(duì)Rust錯(cuò)誤處理相關(guān)知識(shí)感興趣的朋友一起看看吧
    2023-09-09
  • Rust 標(biāo)準(zhǔn)庫(kù)的結(jié)構(gòu)及模塊路徑詳解

    Rust 標(biāo)準(zhǔn)庫(kù)的結(jié)構(gòu)及模塊路徑詳解

    在 Rust 中,標(biāo)準(zhǔn)庫(kù)提供了一組核心功能,以幫助開(kāi)發(fā)者執(zhí)行常見(jiàn)的編程任務(wù),這個(gè)路徑樹(shù)可以作為參考,幫助你更好地理解 Rust 標(biāo)準(zhǔn)庫(kù)的結(jié)構(gòu)和模塊之間的關(guān)系,本文介紹 Rust 標(biāo)準(zhǔn)庫(kù)的結(jié)構(gòu),并提供相應(yīng)的 use 路徑,感興趣的朋友一起看看吧
    2024-05-05
  • Rust生成隨機(jī)數(shù)的項(xiàng)目實(shí)踐

    Rust生成隨機(jī)數(shù)的項(xiàng)目實(shí)踐

    Rust標(biāo)準(zhǔn)庫(kù)中并沒(méi)有隨機(jī)數(shù)生成器,常見(jiàn)的解決方案是使用rand包,本文主要介紹了Rust生成隨機(jī)數(shù)的項(xiàng)目實(shí)踐,具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-03-03

最新評(píng)論

平泉县| 渑池县| 武乡县| 龙门县| 溧阳市| 宁阳县| 银川市| 永康市| 安仁县| 团风县| 洪湖市| 舒城县| 兴城市| 永仁县| 翁源县| 资兴市| 富宁县| 安陆市| 米易县| 柳州市| 成武县| 军事| 泽库县| 开封市| 宜州市| 嘉禾县| 新田县| 文成县| 高碑店市| 沙湾县| 马尔康县| 双柏县| 怀远县| 瓦房店市| 阳原县| 汝南县| 社旗县| 杭州市| 丘北县| 东方市| 南宫市|