色哟哟视频在线观看-色哟哟视频在线-色哟哟欧美15最新在线-色哟哟免费在线观看-国产l精品国产亚洲区在线观看-国产l精品国产亚洲区久久

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

rust語言基礎學習: rust中的錯誤處理

冬至子 ? 來源:山川與湖水 ? 作者:山川與湖水 ? 2023-05-22 16:28 ? 次閱讀

錯誤是軟件中不可避免的,所以 Rust 有一些處理出錯情況的特性。在許多情況下,Rust 要求你承認錯誤的可能性,并在你的代碼編譯前采取一些行動。這一要求使你的程序更加健壯,因為它可以確保你在將代碼部署到生產環境之前就能發現錯誤并進行適當的處理。

Rust中的錯誤可分為可 恢復錯誤 (recoverable)和 不可恢復錯誤 (unrecoverable)

可恢復錯誤代表一種可以恢復的情況下失敗,可以向用戶報告問題并重試操作,例如未找到文件;

不可恢復錯誤代表一種不可處理的狀態,會導致程序 崩2 ,例如嘗試訪問超過數組結尾的位置;

對比其他編程語言的錯誤處理:
1. Java語言采用了異常機制的方式來處理,并沒有明確區分可恢復錯誤和不可恢復錯誤。
(ps: 雖然Java的異常給出了Throwable, Error, Exception, RuntimeException的
繼承關系體系,異常分為checked exception和uncheced exceppion,但在異常傳播上
采用的是通過棧回溯的方式一層層傳遞,直到出現捕獲異常的地方。) Java語言這種異常
處理方式的優點是簡化了錯誤處理流程,但在運行時開銷比使用返回值返回錯誤信息的方式要大很多。
2. Go語言是明確區分可恢復錯誤(error)和不可恢復錯誤(panic)的。Go對可恢復錯誤
采用了以函數返回錯誤值的形式,在函數返回時額外返回一個錯誤對象(error),這種方式的優點
是錯誤處理的運行時開銷小,缺點是返回的錯誤必須處理或者顯式傳播返回給上級調用,
因此一個Go程序代碼中會有大量的if err!= nil {return err;}。

Rust中沒有異常,對于可恢復錯誤使用了類型Result,即函數返回的錯誤信息通過類型系統描述。對于在程序遇到不可恢復的錯誤時panic!時停止執行

1. Result和可恢復錯誤

Result是一個枚舉類型,其定義如下:

#[derive(Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)]
#[must_use = "this `Result` may be an `Err` variant, which should be handled"]
#[rustc_diagnostic_item = "result_type"]
#[stable(feature = "rust1", since = "1.0.0")]
pub enum Result

Result枚舉有兩個成員,OkErrTE是泛型參數T代表成功返回的Ok成員中的數據類型。E代表失敗返回的Err成員中的錯誤的類型。有了這兩個泛型參數,可以將Result枚舉作為函數的返回值,用于各種場景下的可恢復錯誤的處理,當函數成功時返回Ok(T),失敗時返回Err(E)

Result的定義上面有一個must_use的標注,rust的編譯器會對must_use標注的類型做特殊處理,如果該類型對應的值沒有被顯式使用,則就會有一個警告。例如下面的代碼。

fn foo() -> Result<(), String> {
    Ok(())
}


fn main() {
    foo(); // unused `std::result::Result` that must be used
}

代碼在調用foo函數時,忽略了返回值Result,因為Result上有must_use標注,所以Rust的編譯器在編譯時會報一個警告:

warning: unused `Result` that must be used
 --> src/main.rs:7:5
  |
7 |     foo(); // unused `std::result::Result` that must be used
  |     ^^^^^^
  |
  = note: `#[warn(unused_must_use)]` on by default
  = note: this `Result` may be an `Err` variant, which should be handled

1.1 匹配不同的錯誤原因

在處理錯誤時,很多時候需要針對不同的錯誤原因進行不同的處理。下面來學習一下rust標準庫中的std::io module中是如何設計錯誤處理的。

std::io中定義了一個std::io::Result:

#[stable(feature = "rust1", since = "1.0.0")]
pub type Result

io::Result的定義可以看出,io::Result實際上是result::Result的別名。 io::Result中的Err成員類型是io::Error

io::Error是一個結構體,它由一個kind()方法簽名是pub fn kind(&self) -> ErrorKind,返回描述錯誤原因枚舉ErrorKind

ErrorKind的成員是各種io錯誤原因,比如NotFound, PermissionDenied

因此如果函數返回io::Result,失敗時返回的是io::Error時,就可以調用kind方法,進一步匹配不同的錯誤原因進行不同處理。

use std::fs::File;
use std::io::ErrorKind;


fn main() {
    let f = File::open("hello.txt").unwrap_or_else(|err| {
        match err.kind() {
            ErrorKind::NotFound => File::create("hello.tx").unwrap_or_else(|error| {
                panic!("Problem creating the file: {:?}", error);
            }), // 匹配錯誤原因, 對于文件不存在的錯誤處理為創建文件
            other_error_kind => panic!("Problem opening the file: {:?}", other_error_kind)
        }
    });
    println!("{:?}", f);
}

例2中還用到了Result的unwrap_or_else方法,Result類型定義了很多輔助方法來處理各種情況。除了unwrap_or_else外,還有:

  • unwrap方法: 如果Result的值是成員Okunwrap就返回Ok的值;如果Result的值是成員Errunwrap就會調用panic!
  • expect方法: 與unwrap的使用方式一樣,允許我們傳參指定panic!的信息

1.2 使用?操作符傳播錯誤

經常在編寫一個函數實現時會調用另一個返回Result的函數,除了在這個函數中處理錯誤之外,還可以選擇將錯誤傳播到上游調用者,這就是傳播錯誤。

rust還提供了強大的?操作符,如果我們只想要傳播錯誤,而不想直接處理,可以使用?操作符。

use std::io;
use std::io::Read;
use std::fs::File;


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

代碼中第6行的?操作符會被展開成類似下面的代碼:

match result {
    Ok(v) => v,
    Err(e) => Err(e.into())
}
```Result 值之后的 ? 作用為與 match 表達式有著完全相同的工作方式。如果 Result 的值是 Ok,這個表達式將會返回 Ok 中的值而程序將繼續執行。如果值是 ErrErr 中的值將作為整個函數的返回值,就好像使用了 return 關鍵字一樣,這樣錯誤值就被傳播給了調用者。

match 表達式與 ? 運算符所做的有一點不同:? 運算符所使用的錯誤值被傳遞給了 from 函數,它定義于標準庫的 From trait 中,其用來將錯誤從一種類型轉換為另一種類型。當 ? 運算符調用 from 函數時,收到的錯誤類型被轉換為由當前函數返回類型所指定的錯誤類型。

## 2. panic! 和不可恢復錯誤

突然有一天,代碼出問題了,程序崩潰,對于這種情況,Rust提供了一個panic!宏,當執行這個宏時,程序會打印出一個錯誤信息,展開并清理棧數據,然后接著退出。出現這種情況的場景通常是檢測到一些類型的 bug,Rust程序員可以讓 Rust 在 panic 發生時打印調用堆棧(call stack)以便于定位 panic 的原因。

在實踐中有兩種方法造成 panic:

* 執行會造成代碼 panic 的操作,比如訪問超過數組結尾的內容
* 顯式調用 panic! 宏,比如`panic!("crash and burn");`。

panic!表示不可恢復的錯誤,希望程序馬上終止運行并得到崩潰信息。

rust標準庫還提供了`catch_unwind()`,可以把panic的調用棧回溯到catch_unwind的時候。

use std::panic;

fn main() {

let result = panic::catch_unwind(|| {

panic!("crash");

});

if result.is_err() {

println!("panic reover: {:#?}", result);

}

println!("exit ok!");

}

代碼運行結果如下:

thread 'main' panicked at 'crash', src/main.rs:4:9

note: run with RUST_BACKTRACE=1 environment variable to display

a backtracepanic reover: Err(

Any { .. },

)

exit ok!

### 2.1 使用 `panic!` 的 backtrace

可以使用 `RUST_BACKTRACE=1 cargo run` 來得到一個 backtrace,backtrace 是一個執行到目前位置所有被調用的函數的列表。Rust 的 backtrace 跟其他語言中的一樣:閱讀 backtrace 的關鍵是從頭開始讀直到發現你編寫的文件。這就是問題的發源地。這一行往上是你的代碼所調用的代碼;往下則是調用你的代碼的代碼。這些行可能包含核心 Rust 代碼,標準庫代碼或用到的 crate 代碼。

// src/main.rs

fn main() {

let v = vec![1, 2, 3];

v[99];

}

$ RUST_BACKTRACE=1 cargo run

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/e092d0b6b43f2de967af0887873151bb1c0b18d3/library/std/src/panicking.rs:584:5

1: core::panicking::panic_fmt at /rustc/e092d0b6b43f2de967af0887873151bb1c0b18d3/library/core/src/panicking.rs:142:14

2: core::panicking::panic_bounds_check at /rustc/e092d0b6b43f2de967af0887873151bb1c0b18d3/library/core/src/panicking.rs:84:5

3: >::index at /rustc/e092d0b6b43f2de967af0887873151bb1c0b18d3/library/core/src/slice/index.rs:242:10

4: core::slice::index:: for [T]>::index at /rustc/e092d0b6b43f2de967af0887873151bb1c0b18d3/library/core/src/slice/index.rs:18:9

5: [alloc::vec::Vec as core::ops::index::Index*>::index at /rustc/e092d0b6b43f2de967af0887873151bb1c0b18d3/library/alloc/src/vec/mod.rs:2591:9

6: panic::main at ./src/main.rs:4:5

7: core::ops::function::FnOnce::call_once at /rustc/e092d0b6b43f2de967af0887873151bb1c0b18d3/library/core/src/ops/function.rs:248:5

note: Some details are omitted, run with RUST_BACKTRACE=full for a verbose backtrace.*](alloc::vec::Vec%3CT,A)

[**

## 總結

Rust 的錯誤處理功能被設計為幫助你編寫更加健壯的代碼。`panic!` 宏代表一個程序**無法處理**的狀態,并停止執行而不是使用無效或不正確的值繼續處理。Rust 類型系統的 `Result` 枚舉代表操作可能會在一種**可以恢復**的情況下失敗,可以使用 `Result` 來告訴代碼調用者他需要處理潛在的成功或失敗。在適當的場景使用 `panic!``Result` 將會使你的代碼在面對不可避免的錯誤時顯得更加可靠。

* 可恢復錯誤:想向用戶報告問題并**重試**操作,Result處理;
* 不可恢復錯誤:導致程序**崩潰的**panic,catch_unwind() 棧回溯;
* match匹配: 處理返回值`Result`,**匹配**出不同錯誤的原因;
* ?運算符: **傳播錯誤** ,將錯誤從一種類型轉換為另一種類型,返回給調用者;

**](alloc::vec::Vec%3CT,A)

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • JAVA
    +關注

    關注

    19

    文章

    2966

    瀏覽量

    104702
  • 編譯器
    +關注

    關注

    1

    文章

    1623

    瀏覽量

    49108
  • rust語言
    +關注

    關注

    0

    文章

    57

    瀏覽量

    3009
收藏 人收藏

    評論

    相關推薦

    聊聊Rust與C語言交互的具體步驟

    rust FFI 是rust與其他語言互調的橋梁,通過FFI rust 可以有效繼承 C 語言的歷史資產。本期通過幾個例子來聊聊
    發表于 07-06 11:15 ?1705次閱讀

    Rust語言錯誤處理的機制

    可能的錯誤,實際運行仍然可能出現各種各樣的錯誤,比如文件不存在、網絡連接失敗等等。對于這些不可預測的錯誤,我們必須使用錯誤處理機制來進行
    的頭像 發表于 09-19 14:54 ?1404次閱讀

    基于Rust語言Hash特征的基礎用法和進階用法

    Rust語言是一種系統級編程語言,具有高性能、安全、并發等特點,是近年來備受關注的新興編程語言。在Rust
    的頭像 發表于 09-19 16:02 ?1441次閱讀

    Rust語言如何與 InfluxDB 集成

    的數據處理和存儲能力。 本教程將介紹 Rust 語言如何與 InfluxDB 集成,包括基礎用法和進階用法和完整的示例代碼。 基礎用法 安裝 InfluxDB Rust 客戶端 首先,
    的頭像 發表于 09-30 16:45 ?1153次閱讀

    基于Rust語言中的生命周期

    Rust是一門系統級編程語言具備高效、安和并發等特,而生命周期是這門語言中比較重要的概念之一。在這篇教程,我們會了解什么是命周期、為什么需要生命周期、如何使用生命周期,同時我們依然會
    的頭像 發表于 09-19 17:03 ?897次閱讀

    Rust的 match 語句用法

    執行不同的代碼,這在處理復雜的邏輯時非常有用。在本教程,我們將深入了解 Rust 的 match 語句,包括基礎用法、進階用法和實踐經驗等方面。 基礎用法 match 語句是 Rust
    的頭像 發表于 09-19 17:08 ?909次閱讀

    只會用Python?教你在樹莓派上開始使用Rust

    如果您對編程感興趣,那么您可能聽說過Rust。該語言由Mozilla設計,受到開發人員的廣泛喜愛,并繼續在奉獻者成長。Raspberry Pi是小型計算機的瑞士軍刀,非常適合學習代碼
    發表于 05-20 08:00

    如何用 rust 語言開發 stm32

    本文介紹如何用 rust 語言開發 stm32。開發平臺為 linux(gentoo)。硬件準備本文使用的芯片為 STM32F103C8T6。該芯片性價比較高,價格低廉,適合入門學習。需要
    發表于 11-26 06:20

    RUST在嵌入式開發的應用是什么

    Rust是一種編程語言,它使用戶能夠構建可靠、高效的軟件,尤其是用于嵌入式開發的軟件。它的特點是:高性能:Rust具有驚人的速度和高內存利用率。可靠性:在編譯過程可以消除內存
    發表于 12-24 08:34

    如何利用C語言去調用rust靜態庫呢

    語言的感覺,要做不少的對接工作。也用過Lua,感覺也差不多。評估學習評估Rust語言時,感覺性能和體積應該都不會有太大的問題。加上語言本身
    發表于 06-21 10:27

    Rust代碼中加載靜態庫時,出現錯誤 ` rust-lld: error: undefined symbol: malloc `怎么解決?

    時,出現錯誤 ` [i]rust-lld: error: undefined symbol: malloc `。如何將這些定義包含在我的靜態庫
    發表于 06-09 08:44

    微軟開發基于Rust的新編程語言,將很快開源

    使用Rust重寫各種產品,因為在過去的十年里,微軟70%以上的安全補丁都提供了與內存相關的錯誤,而Rust正是解決這個問題的良藥。 而根據ZDNet的報導,近日在一次演講,談到微軟為
    的頭像 發表于 12-03 10:36 ?3915次閱讀

    以調試Rust的方式來學習Rust

    在我上一篇 關于 Rustup 的文章 ,我向你們展示了如何安裝 Rust 工具鏈。但是,如果不能上手操作一下 Rust 的話下載工具鏈又有什么用?學習任何
    的頭像 發表于 01-03 14:56 ?906次閱讀

    Rust錯誤處理方法

    Rust 沒有提供類似于 Java、C++ 的 Exception 機制,而是使用 Result 枚舉的方式來實現。
    的頭像 發表于 02-20 09:37 ?945次閱讀

    rust語言基礎學習: 智能指針之Cow

    Rust與借用數據相關的三個trait: Borrow, BorrowMut和ToOwned。理解了這三個trait之后,再學習Rust
    的頭像 發表于 05-22 16:13 ?2904次閱讀
    主站蜘蛛池模板: 国产欧美日韩亚洲第一页| www色视频在线观看| 全部免费特黄特色大片看片| 高H纯肉NP 弄潮NP男男| 亚洲成人精品久久| 成 人 免费 黄 色 网站无毒下载| 日日噜噜噜噜夜夜爽亚洲精品| 国产色综合色产在线视频| 永久免费在线视频| 欧美一道本一区二区三区| 国产乱码伦人偷精品视频| 在线二区 中文 无码| 青青青草国产| 国产在线不卡| 亚洲国产在线视频精品| 伦理片在线线手机版韩国免费观看 | 亚洲白色白色在线播放| 久久亚洲AV成人无码国产漫画| xx在线观看| 亚洲国产高清在线| 男人天堂999| 国产精品爽黄69天堂A片| 中国人泡妞xxxxxxxx19| 色爱AV综合区| 精品久久综合1区2区3区激情| a级男女性高爱潮高清试看| 午夜宅宅伦电影网| 乱码午夜-极品国产内射| 国产成人久久精品激情| 诱受H嗯啊巨肉舍友1V1| 日本一区精品久久久久影院| 九九热免费在线观看| 变态露出野外调教| 亚洲一区在线观看无码欧美| 青娱乐国产精品视频| 红尘影院手机在线观看| www.色片| 一二三四在线视频社区8| 日韩人妻双飞无码精品久久| 久久久久久久电影| 国产精品无码人妻在线|