一区二区三区三上|欧美在线视频五区|国产午夜无码在线观看视频|亚洲国产裸体网站|无码成年人影视|亚洲AV亚洲AV|成人开心激情五月|欧美性爱内射视频|超碰人人干人人上|一区二区无码三区亚洲人区久久精品

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

Rust中的錯(cuò)誤處理方法

jf_wN0SrCdH ? 來源:Rust語言中文社區(qū) ? 2023-02-20 09:37 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

Rust中的錯(cuò)誤處理

Result枚舉

Rust 中沒有提供類似于 Java、C++ 中的 Exception 機(jī)制,而是使用Result枚舉的方式來實(shí)現(xiàn):


	

pub enum Result { /// Contains the success value Ok(T), /// Contains the error value Err(E), }

在使用時(shí):

  • 如果無錯(cuò)誤則使用Ok(T)返回;

  • 如果存在錯(cuò)誤,則使用Err(E)包裝錯(cuò)誤類型返回;

例如:

examples/0_result.rs


	

#[derive(Debug)] pub enum MyError { Internal(String), InvalidId(String), } fn add(num: i64) -> Result<i64, MyError> { if num < 0 { Err(MyError::InvalidId(String::from("Invalid num!"))) } else { Ok(num + 100000) } } fn main() -> Result<(), MyError> { // fetch_id(-1)?; let res = add(1)?; println!("{}", res); Ok(()) }

上面的代碼首先通過 MyError 枚舉定義了多個(gè)可能會出現(xiàn)的錯(cuò)誤;

隨后,在add函數(shù)中:

  • 當(dāng) num 小于 0 時(shí)返回錯(cuò)誤;

  • 否則給 num 增加 100000 并返回;

在上面的let res = add(1)?;中使用了?操作符,他相當(dāng)于是一個(gè)語法糖:

  • 如果被調(diào)函數(shù)正常返回則調(diào)用unwrap獲取其值;

  • 反之,則將被調(diào)函數(shù)的錯(cuò)誤直接向上返回(相當(dāng)于直接 return Err);

即上面的語法糖相當(dāng)于:


	

let res = match add() { Ok(id) => id, Err(err) => { return Err(err); } };

錯(cuò)誤類型轉(zhuǎn)換

上面簡單展示了 Rust 中錯(cuò)誤的使用;

由于 Rust 是強(qiáng)類型的語言,因此如果在一個(gè)函數(shù)中使用?返回了多個(gè)錯(cuò)誤,并且他們的類型是不同的,還需要對返回的錯(cuò)誤類型進(jìn)行轉(zhuǎn)換,轉(zhuǎn)為相同的類型!

例如下面的例子:


	

#[derive(Debug)] pub enum MyError { ReadError(String), ParseError(String), } fn read_file() -> Result<i64, MyError> { // Error: Could not get compiled! let content = fs::read_to_string("/tmp/id")?; let id = content.parse::<i64>()?; } fn main() -> Result<(), MyError> { let id = read_file()?; println!("id: {}", id); Ok(()) }

上面的例子無法編譯通過,原因在于:read_to_stringparse返回的是不同類型的錯(cuò)誤!

因此,如果要能返回,我們需要對每一個(gè)錯(cuò)誤進(jìn)行轉(zhuǎn)換,轉(zhuǎn)為我們所定義的 Error 類型;

例如:

examples/1_error_convert.rs


	

fn read_file() -> Result<i64, MyError> { // Error: Could not get compiled! // let content = fs::read_to_string("/tmp/id")?; // let id = content.parse::()?; // Method 1: Handling error explicitly! let content = match std::read_to_string("/tmp/id") { Ok(content) => content, Err(err) => { return Err(MyError::ReadError(format!("read /tmp/id failed: {}", err))); } }; let content = content.trim(); println!("read content: {}", content); // Method 2: Use map_err to transform error type let id = content .parse::<i64>() .map_err(|err| MyError::ParseError(format!("parse error: {}", err)))?; Ok(id) }

上面展示了兩種不同的轉(zhuǎn)換 Error 的方法:

方法一通過 match 匹配手動的對read_to_string函數(shù)的返回值進(jìn)行處理,如果發(fā)生了 Error,則將錯(cuò)誤轉(zhuǎn)為我們指定類型的錯(cuò)誤;

方法二通過map_err的方式,如果返回的是錯(cuò)誤,則將其轉(zhuǎn)為我們指定的類型,這時(shí)就可以使用?返回了;

相比之下,使用 map_err 的方式,代碼會清爽很多!

From Trait

上面處理錯(cuò)誤的方法,每次都要對錯(cuò)誤的類型進(jìn)行轉(zhuǎn)換,比較麻煩;

Rust 中提供了 From Trait,在進(jìn)行類型匹配時(shí),如果提供了從一個(gè)類型轉(zhuǎn)換為另一個(gè)類型的方法(實(shí)現(xiàn)了某個(gè)類型的 From Trait),則在編譯階段,編譯器會調(diào)用響應(yīng)的函數(shù),直接將其轉(zhuǎn)為相應(yīng)的類型!

例如:

examples/2_from_trait.rs


	

#[derive(Debug)] pub enum MyError { ReadError(String), ParseError(String), } impl From for MyError { fn from(source: std::Error) -> Self { MyError::ReadError(source.to_string()) } } impl From for MyError { fn from(source: std::ParseIntError) -> Self { MyError::ParseError(source.to_string()) } } fn read_file() -> Result<i64, MyError> { let _content = fs::read_to_string("/tmp/id")?; let content = _content.trim(); let id = content.parse::<i64>()?; Ok(id) } fn main() -> Result<(), MyError> { let id = read_file()?; println!("id: {}", id); Ok(()) }

在上面的代碼中,我們?yōu)?MyError 類型的錯(cuò)誤分別實(shí)現(xiàn)了轉(zhuǎn)換為std::Errorstd::ParseIntError類型的 From Trait;

因此,在 read_file 函數(shù)中就可以直接使用?向上返回錯(cuò)誤了!

但是上面的方法需要為每個(gè)錯(cuò)誤實(shí)現(xiàn) From Trait 還是有些麻煩,因此出現(xiàn)了thiserror以及anyhow庫來解決這些問題;

其他第三方庫

thiserror

上面提到了我們可以為每個(gè)錯(cuò)誤實(shí)現(xiàn) From Trait 來直接轉(zhuǎn)換錯(cuò)誤類型,thiserror庫就是使用這個(gè)邏輯;

我們可以使用 thiserror 庫提供的宏來幫助我們生成到對應(yīng)類型的 Trait;

例如:

examples/3_thiserror.rs


	

#[derive(thiserror::Error, Debug)] pub enum MyError { #[error("io error.")] IoError(#[from] std::Error), #[error("parse error.")] ParseError(#[from] std::ParseIntError), } fn read_file() -> Result<i64, MyError> { // Could get compiled! let content = fs::read_to_string("/tmp/id")?; let id = content.parse::<i64>()?; Ok(id) } fn main() -> Result<(), MyError> { let id = read_file()?; println!("id: {}", id); Ok(()) }

我們只需要對我們定義的類型進(jìn)行宏標(biāo)注,在編譯時(shí)這些宏會自動展開并實(shí)現(xiàn)對應(yīng)的 Trait;

展開后的代碼如下:


	

#![feature(prelude_import)] #[prelude_import] use std::*; #[macro_use] extern crate std; use std::fs; pub enum MyError { #[error("io error.")] IoError(#[from] std::Error), #[error("parse error.")] ParseError(#[from] std::ParseIntError), } #[allow(unused_qualifications)] impl std::Error for MyError { fn source(&self) -> std::Option<&(dyn std::Error + 'static)> { use thiserror::AsDynError; #[allow(deprecated)] match self { MyError::IoError { 0: source, .. } => std::Option::Some(source.as_dyn_error()), MyError::ParseError { 0: source, .. } => { std::Option::Some(source.as_dyn_error()) } } } } #[allow(unused_qualifications)] impl std::Display for MyError { fn fmt(&self, __formatter: &mut std::Formatter) -> std::Result { #[allow(unused_variables, deprecated, clippy::used_underscore_binding)] match self { MyError::IoError(_0) => { let result = __formatter.write_fmt(::new_v1(&["io error."], &[])); result } MyError::ParseError(_0) => { let result = __formatter.write_fmt(::new_v1(&["parse error."], &[])); result } } } } #[allow(unused_qualifications)] impl std::From for MyError { #[allow(deprecated)] fn from(source: std::Error) -> Self { MyError::IoError { 0: source } } } #[allow(unused_qualifications)] impl std::From for MyError { #[allow(deprecated)] fn from(source: std::ParseIntError) -> Self { MyError::ParseError { 0: source } } } #[automatically_derived] #[allow(unused_qualifications)] impl ::Debug for MyError { fn fmt(&self, f: &mut ::Formatter) -> ::Result { match (&*self,) { (&MyError::IoError(ref __self_0),) => { ::debug_tuple_field1_finish(f, "IoError", &&*__self_0) } (&MyError::ParseError(ref __self_0),) => { ::debug_tuple_field1_finish(f, "ParseError", &&*__self_0) } } } } fn read_file() -> Result<i64, MyError> { let content = fs::read_to_string("/tmp/id")?; let id = content.parse::<i64>()?; Ok(id) } #[allow(dead_code)] fn main() -> Result<(), MyError> { let id = read_file()?; { ::new_v1( &["id: ", " "], &[::new_display(&id)], )); }; Ok(()) } #[rustc_main] pub fn main() -> () { extern crate test; test::test_main_static(&[]) }

可以看到實(shí)際上就是為 MyError 實(shí)現(xiàn)了對應(yīng)錯(cuò)誤類型的 From Trait;

thiserror 庫的這種實(shí)現(xiàn)方式,還需要為類型指定要轉(zhuǎn)換的錯(cuò)誤類型;

而下面看到的 anyhow 庫,可以將錯(cuò)誤類型統(tǒng)一為同一種形式;

anyhow

如果你對 Go 中的錯(cuò)誤類型不陌生,那么你就可以直接上手 anyhow 了!

來看下面的例子:

examples/4_anyhow.rs


	

use anyhow::Result; use std::fs; fn read_file() -> Result<i64> { // Could get compiled! let content = fs::read_to_string("/tmp/id")?; let id = content.parse::<i64>()?; Ok(id) } fn main() -> Result<()> { let id = read_file()?; println!("id: {}", id); Ok(()) }

注意到,上面的 Result 類型為anyhow::Result,而非標(biāo)準(zhǔn)庫中的 Result 類型!

anyhowResult實(shí)現(xiàn)了ContextTrait:


	

impl Context for Result where E: ext::StdError + Send + Sync + 'static, { fn context(self, context: C) -> Result where C: Display + Send + Sync + 'static, { // Not using map_err to save 2 useless frames off the captured backtrace // in ext_context. match self { Ok(ok) => Ok(ok), Err(error) => Err(error.ext_context(context)), } } fn with_context(self, context: F) -> Result where C: Display + Send + Sync + 'static, F: FnOnce() -> C, { match self { Ok(ok) => Ok(ok), Err(error) => Err(error.ext_context(context())), } } }

Context中提供了context函數(shù),并且將原來的Result轉(zhuǎn)成了Result;

因此,最終將錯(cuò)誤類型統(tǒng)一為了anyhow::Error類型;

附錄

源代碼:

  • https://github.com/JasonkayZK/rust-learn/tree/error

審核編輯:湯梓紅


聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報(bào)投訴
  • JAVA
    +關(guān)注

    關(guān)注

    20

    文章

    2988

    瀏覽量

    109208
  • 函數(shù)
    +關(guān)注

    關(guān)注

    3

    文章

    4379

    瀏覽量

    64736
  • C++
    C++
    +關(guān)注

    關(guān)注

    22

    文章

    2119

    瀏覽量

    75178
  • 枚舉
    +關(guān)注

    關(guān)注

    0

    文章

    16

    瀏覽量

    4716
  • Rust
    +關(guān)注

    關(guān)注

    1

    文章

    233

    瀏覽量

    7073

原文標(biāo)題:[Rust筆記] Rust中的錯(cuò)誤處理

文章出處:【微信號:Rust語言中文社區(qū),微信公眾號:Rust語言中文社區(qū)】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評論

    相關(guān)推薦
    熱點(diǎn)推薦

    嵌入式編程錯(cuò)誤處理機(jī)制設(shè)計(jì)

    本文主要總結(jié)嵌入式系統(tǒng)C語言編程,主要的錯(cuò)誤處理方式。文中涉及的代碼運(yùn)行環(huán)境如下。
    發(fā)表于 04-28 09:59 ?1002次閱讀
    嵌入式編程<b class='flag-5'>錯(cuò)誤處理</b>機(jī)制設(shè)計(jì)

    嵌入式系統(tǒng)C語言編程主要的錯(cuò)誤處理方式

    本文主要總結(jié)嵌入式系統(tǒng)C語言編程,主要的錯(cuò)誤處理方式。
    發(fā)表于 07-24 16:40 ?1259次閱讀
    嵌入式系統(tǒng)C語言編程<b class='flag-5'>中</b>主要的<b class='flag-5'>錯(cuò)誤處理</b>方式

    Rust語言中錯(cuò)誤處理的機(jī)制

    可能的錯(cuò)誤,實(shí)際運(yùn)行仍然可能出現(xiàn)各種各樣的錯(cuò)誤,比如文件不存在、網(wǎng)絡(luò)連接失敗等等。對于這些不可預(yù)測的錯(cuò)誤,我們必須使用錯(cuò)誤處理機(jī)制來進(jìn)行
    的頭像 發(fā)表于 09-19 14:54 ?1883次閱讀

    嵌入式C編程常用的異常錯(cuò)誤處理

    嵌入式C編程,異常錯(cuò)誤處理是確保系統(tǒng)穩(wěn)定性和可靠性的重要部分。以下是一些常見的異常錯(cuò)誤處理方法及其詳細(xì)說明和示例: 1. 斷言 (Assertions) 斷言用于在開發(fā)階段捕獲程
    發(fā)表于 08-06 14:32

    labviEW錯(cuò)誤處理的問題

    為什么這個(gè)程序在啟用自動錯(cuò)誤處理和C:\data.txt不存在的情況下,沒有顯示錯(cuò)誤對話框???
    發(fā)表于 04-01 10:03

    AF錯(cuò)誤處理

    想問一下關(guān)于AF的錯(cuò)誤處理,例如我進(jìn)行串口通訊,打開串口錯(cuò)誤,但是我不想停止AF,想繼續(xù)嘗試連接要怎么做?
    發(fā)表于 02-03 15:44

    LabVIEW錯(cuò)誤處理

    如何合理使用 LabVIEW 的自定義錯(cuò)誤處理功能;對于可預(yù)見的錯(cuò)誤,是否可以選擇直 接忽略,或者前幾次嘗試忽略直到該特定錯(cuò)誤出現(xiàn)很多次后才通知用戶需要糾正該
    發(fā)表于 05-24 11:07 ?6次下載

    Spring Boot框架錯(cuò)誤處理

    》 《strong》翻譯《/strong》:雁驚寒《/p》 《/blockquote》《p》《em》摘要:本文通過實(shí)例介紹了使用Spring Boot在設(shè)計(jì)API的時(shí)候如何正確地對異常進(jìn)行處理。以下是譯文《/em》《/p》《p》API在提供錯(cuò)誤消息的同時(shí)進(jìn)行適當(dāng)?shù)?/div>
    發(fā)表于 09-28 15:31 ?0次下載

    嵌入式系統(tǒng)C語言編程錯(cuò)誤處理資料總結(jié)

    本文主要總結(jié)嵌入式系統(tǒng)C語言編程,主要的錯(cuò)誤處理方式。文中涉及的代碼運(yùn)行環(huán)境如下:
    發(fā)表于 11-28 10:39 ?2106次閱讀

    Rust代碼啟發(fā)之返回值異常錯(cuò)誤處理

    這樣的代碼,錯(cuò)誤處理代碼和業(yè)務(wù)邏輯交織在一起,也容易忽略處理錯(cuò)誤。以及把返回值只用于錯(cuò)誤返回,有點(diǎn)浪費(fèi)的感覺。因?yàn)楹芏鄷r(shí)候把計(jì)算結(jié)果作為返回值,更符合思考的邏輯。
    的頭像 發(fā)表于 09-22 09:24 ?2491次閱讀
    <b class='flag-5'>Rust</b>代碼啟發(fā)之返回值異常<b class='flag-5'>錯(cuò)誤處理</b>

    rust語言基礎(chǔ)學(xué)習(xí): rust錯(cuò)誤處理

    錯(cuò)誤是軟件不可避免的,所以 Rust 有一些處理出錯(cuò)情況的特性。在許多情況下,Rust 要求你承認(rèn)錯(cuò)誤
    的頭像 發(fā)表于 05-22 16:28 ?2506次閱讀

    RS232通信時(shí)怎么處理錯(cuò)誤?RS232通信中的錯(cuò)誤處理方法

    RS232通信時(shí)怎么處理錯(cuò)誤?RS232通信中的錯(cuò)誤處理方法? RS232通信是一種電氣標(biāo)準(zhǔn),它定義了計(jì)算機(jī)和串行通信設(shè)備之間的通信協(xié)議。盡管RS232通信很穩(wěn)定,但仍然可能會出現(xiàn)
    的頭像 發(fā)表于 10-17 16:33 ?3842次閱讀

    西門子博圖:錯(cuò)誤處理機(jī)制概覽

    可通過以下幾種不同的錯(cuò)誤處理機(jī)制進(jìn)行參數(shù)跟蹤或編程或訪問錯(cuò)誤
    的頭像 發(fā)表于 11-25 11:35 ?4038次閱讀
    西門子博圖:<b class='flag-5'>錯(cuò)誤處理</b>機(jī)制概覽

    C語言中的錯(cuò)誤處理機(jī)制解析

    C 語言不提供對錯(cuò)誤處理的直接支持,但是作為一種系統(tǒng)編程語言,它以返回值的形式允許您訪問底層數(shù)據(jù)。
    的頭像 發(fā)表于 02-26 11:19 ?775次閱讀

    socket編程錯(cuò)誤處理技巧

    Socket編程是網(wǎng)絡(luò)編程的基礎(chǔ),它允許程序之間通過TCP/IP協(xié)議進(jìn)行通信。然而,網(wǎng)絡(luò)通信是不穩(wěn)定的,可能會遇到各種問題,如網(wǎng)絡(luò)延遲、連接中斷、數(shù)據(jù)丟失等。 錯(cuò)誤處理的重要性 提高程序的健壯性
    的頭像 發(fā)表于 11-01 17:47 ?1523次閱讀