国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

Rust錯誤處理

這篇具有很好參考價值的文章主要介紹了Rust錯誤處理。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

返回值和錯誤處理

panic 深入剖析

主動調(diào)用
fn main() {
    panic!("crash and burn");
}
backtrace 棧展開
panic 時的兩種終止方式

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

何時該使用 panic!

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

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

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

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

返回值和?

對返回的錯誤進行處理
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 后,又對 error 進行了詳細(xì)的匹配解析,最終結(jié)果:

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

在不需要處理錯誤的場景,例如寫原型、示例時,我們不想使用 match 去匹配 Result<T, E> 以獲取其中的 T 值,因為 match 的窮盡匹配特性,你總要去處理下 Err 分支。那么有沒有辦法簡化這個過程?有,答案就是 unwrap 和 expect。

use std::fs::File;

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

如果調(diào)用這段代碼時 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 很像,也是遇到錯誤直接 panic, 但是會帶上自定義的錯誤提示信息,相當(dāng)于重載了錯誤打印的函數(shù):

use std::fs::File;

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

報錯如下:

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

傳播錯誤

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

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

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

fn read_username_from_file() -> Result<String, io::Error> {
    // 打開文件,f是`Result<文件句柄,io::Error>`
    let f = File::open("hello.txt");

    let mut f = match f {
        // 打開文件成功,將file句柄賦值給f
        Ok(file) => file,
        // 打開文件失敗,將錯誤返回(向上傳播)
        Err(e) => return Err(e),
    };
    // 創(chuàng)建動態(tài)字符串s
    let mut s = String::new();
    // 從f文件句柄讀取數(shù)據(jù)并寫入s中
    match f.read_to_string(&mut s) {
        // 讀取成功,返回Ok封裝的字符串
        Ok(_) => Ok(s),
        // 將錯誤向上傳播
        Err(e) => Err(e),
    }
}

有幾點值得注意:

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

。

傳播界的大明星: ?

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)
}

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

其實 ? 就是一個宏,它的作用跟上面的 match 幾乎一模一樣:

let mut f = match f {
    // 打開文件成功,將file句柄賦值給f
    Ok(file) => file,
    // 打開文件失敗,將錯誤返回(向上傳播)
    Err(e) => return Err(e),
};

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

雖然 ? 和 match 功能一致,但是事實上 ? 會更勝一籌。

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

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

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

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

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

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

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)
}

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

use std::fs;
use std::io;

fn read_username_from_file() -> Result<String, io::Error> {
    // read_to_string是定義在std::io中的方法,因此需要在上面進行引用
    fs::read_to_string("hello.txt")
}

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

? 用于 Option 的返回

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

pub enum Option<T> {
    Some(T),
    None
}

Result 通過 ? 返回錯誤,那么 Option 就通過 ? 返回 None:

fn first(arr: &[i32]) -> Option<&i32> {
   let v = arr.get(0)?;
   Some(v)
}
新手用 ? 常會犯的錯誤

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

fn first(arr: &[i32]) -> Option<&i32> {
   arr.get(0)?
}

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

let v = xxx()?;
xxx()?.yyy()?;
帶返回值的 main 函數(shù)

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

use std::fs::File;

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

運行后會報錯:

$ 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<Result<Infallible, std::io::Error>>` is not implemented for `()`

因為 ? 要求 Result<T, E> 形式的返回值,而 main 函數(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(())
}

這樣就能使用 ? 提前返回了,同時我們又一次看到了Box 特征對象,因為 std::error:Error 是 Rust 中抽象層次最高的錯誤,其它標(biāo)準(zhǔn)庫中的錯誤都實現(xiàn)了該特征,因此我們可以用該特征對象代表一切錯誤,就算 main 函數(shù)中調(diào)用任何標(biāo)準(zhǔn)庫函數(shù)發(fā)生錯誤,都可以通過 Box<dyn Error> 這個特征對象進行返回。文章來源地址http://www.zghlxwxcb.cn/news/detail-741301.html

到了這里,關(guān)于Rust錯誤處理的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

  • 30天拿下Rust之錯誤處理

    30天拿下Rust之錯誤處理

    概述 ????????在軟件開發(fā)領(lǐng)域,對錯誤的妥善處理是保證程序穩(wěn)定性和健壯性的重要環(huán)節(jié)。Rust作為一種系統(tǒng)級編程語言,以其對內(nèi)存安全和所有權(quán)的獨特設(shè)計而著稱,其錯誤處理機制同樣體現(xiàn)了Rust的嚴(yán)謹(jǐn)與實用。在Rust中,錯誤處理通常分為兩大類:不可恢復(fù)的錯誤和可

    2024年03月21日
    瀏覽(19)
  • Rust Web 全棧開發(fā)之 Web Service 中的錯誤處理

    數(shù)據(jù)庫 數(shù)據(jù)庫錯誤 串行化 serde 錯誤 I/O 操作 I/O 錯誤 Actix-Web 庫 Actix 錯誤 用戶非法輸入 用戶非法輸入錯誤 編程語言常用的兩種錯誤處理方式: 異常 返回值( Rust 使用這種) Rust 希望開發(fā)者顯式的處理錯誤,因此,可能出錯的函數(shù)返回Result 枚舉類型,其定義如下: 例子 在

    2024年02月07日
    瀏覽(22)
  • Rust之構(gòu)建命令行程序(三):重構(gòu)改進模塊化和錯誤處理

    Rust之構(gòu)建命令行程序(三):重構(gòu)改進模塊化和錯誤處理

    Windows 10 Rust 1.74.1 ? VS Code 1.85.1 這次創(chuàng)建了新的工程minigrep. 為了改進我們的程序,我們將修復(fù)與程序結(jié)構(gòu)及其處理潛在錯誤的方式有關(guān)的四個問題。首先,我們的 main 函數(shù)現(xiàn)在執(zhí)行兩項任務(wù):解析參數(shù)和讀取文件。隨著我們程序的增長, main 處理的獨立任務(wù)的數(shù)量也會增加。隨

    2024年01月18日
    瀏覽(106)
  • Rust腐蝕申述教程Rust被辦申述處理

    Rust腐蝕申述教程Rust被辦申述處理

    玩Rust很難避免被辦,但有些被辦是理所當(dāng)。例如:開G、開宏或者其他作弊行為影響了游戲平衡,本指南主要針對綠色玩家被誤封的情況。 一、不同類型的封禁 首先要了解不同的封禁類型,并不是所有的封禁都是公平公正的,特別是國人在外服或者社區(qū)服游戲時經(jīng)常被辦出服

    2024年02月06日
    瀏覽(16)
  • Rust處理JSON

    Rust處理JSON

    基本操作 Cargo.toml: main.rs: 輸出為: 嵌套結(jié)構(gòu)體 warp [1] 返回不同的結(jié)構(gòu)(一般用枚舉來解決) 參考資料 [1] warp: https://github.com/seanmonstar/warp 本文由 mdnice 多平臺發(fā)布

    2024年02月11日
    瀏覽(18)
  • rust版本更新錯誤記錄:Os { code: 5, kind: PermissionDenied }

    使用 rustup update 更新 rust 版本時遇到錯誤: info: cleaning up downloads tmp directories thread ‘main’ panicked at ‘Unable to clean up C:UsersGrapeX.rustuptmp: Os { code: 5, kind: PermissionDenied, message: “拒絕訪問?!?}’, srcutilsutils.rs:650:13 stack backtrace: note: Some details are omitted, run with RUST_BACKTRACE=full

    2024年02月16日
    瀏覽(20)
  • RUST Rover 條件編譯 異常處理

    RUST Rover 條件編譯 異常處理

    會報異常 error: failed to parse manifest at C:UserstopmaRustroverProjectsuntitled2Cargo.toml 網(wǎng)上說明 這樣處理 https://course.rs/cargo/reference/features/intro.html RUST 圣經(jīng)里描述

    2024年04月09日
    瀏覽(20)
  • Rust中的高吞吐量流處理

    Rust中的高吞吐量流處理

    本篇文章主要介紹了Rust中流處理的概念、方法和優(yōu)化。作者不僅介紹了流處理的基本概念以及Rust中常用的流處理庫,還使用這些庫實現(xiàn)了一個流處理程序。 最后,作者介紹了如何通過測量空閑和阻塞時間來優(yōu)化流處理程序的性能,并將這些內(nèi)容同步至Twitter和blog。 此外,作

    2024年02月14日
    瀏覽(25)
  • Rust中的字符串處理及相關(guān)方法詳解

    在Rust中,字符串是一種非常重要的數(shù)據(jù)類型,而 String 類型則提供了對動態(tài)可變字符串的支持。本文將介紹一些常見的字符串處理方法以及相關(guān)示例代碼。 在Rust中,有多種方式創(chuàng)建字符串,以下是一些常見的例子: push_str()方法 push_str() 方法用于將一個字符串切片附加到 S

    2024年02月19日
    瀏覽(19)
  • 【Rust】——通過Deref trait將智能指針當(dāng)作常規(guī)引用處理

    ??博主現(xiàn)有專欄: ????????????????C51單片機(STC89C516),c語言,c++,離散數(shù)學(xué),算法設(shè)計與分析,數(shù)據(jù)結(jié)構(gòu),Python,Java基礎(chǔ),MySQL,linux,基于HTML5的網(wǎng)頁設(shè)計及應(yīng)用,Rust(官方文檔重點總結(jié)),jQuery,前端vue.js,Javaweb開發(fā),Python機器學(xué)習(xí)等 ??主頁鏈接: ????

    2024年04月26日
    瀏覽(22)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包