日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Rust错误处理

發(fā)布時間:2025/3/20 编程问答 44 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Rust错误处理 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

Rust錯誤處理

本文同步于Rust中文社區(qū)專欄文章:Rust錯誤處理 ,本文時間:2018-12-14, 譯者:krircc,簡介:天青色,原文出處

歡迎向Rust中文社區(qū)投稿,投稿地址 ,好文將在以下地方直接展示

  • Rust中文社區(qū)首頁
  • Rust中文社區(qū)文章欄目
  • 知乎專欄Rust中文社區(qū)
  • 思否專欄Rust中文社區(qū)
  • 簡書專題Rust中文社區(qū)
  • 微博Rustlang-cn
  • 智能編譯器

    Rust編譯器最重要的工作是防止Rust程序中的錯誤。如果代碼沒有正確遵循內存管理規(guī)則或生命周期注釋,它會在編譯時分析代碼并發(fā)出警告。例如,

    #[allow(unused_variables)] //? A lint attribute used to suppress the warning; unused variable: `b` fn main() {let a = vec![1, 2, 3];let b = a;println!("{:?}", a); }// ------ Compile time error ------ error[E0382]: use of moved value: `a`--> src/main.rs:6:22| 3 | let b = a;| - value moved here 4 | 5 | println!("{:?}", a);| ^ value used here after move|= note: move occurs because `a` has type `std::vec::Vec<i32>`, which does not implement the `Copy` traiterror: aborting due to previous error For more information about this error, try `rustc --explain E0382`.// ? instead using #[allow(unused_variables)], consider using "let _b = a;" in line 4. // Also you can use "let _ =" to completely ignore return values

    Rust編譯器不僅檢查與生命周期或內存管理相關的問題,還檢查常見的編碼錯誤,如下面的代碼。

    struct Color {r: u8,g: u8,b: u8, }fn main() {let yellow = Color {r: 255,g: 255,d: 0,};println!("Yellow = rgb({},{},{})", yellow.r, yellow.g, yellow.b); }// ------------ Compile time error ------------ error[E0560]: struct `Color` has no field named `d`--> src/main.rs:11:9| 11 | d: 0,| ^ field does not exist - did you mean `b`?error: aborting due to previous error For more information about this error, try `rustc --explain E0560`.

    以上錯誤消息非常具有描述性,我們可以很容易地看出錯誤在哪里。但是,雖然我們無法通過錯誤消息識別問題,但rustc --explain 命令通過顯示表達相同問題的簡單代碼示例以及我們必須使用的解決方案來幫助我們識別錯誤類型以及如何解決它。例如,在控制臺中顯示以下輸出。rustc --explain E0571

    // A `break` statement with an argument appeared in a non-`loop` loop.// Example of erroneous code:let result = while true {if satisfied(i) {break 2*i; // error: `break` with value from a `while` loop}i += 1; };// The `break` statement can take an argument (which will be the value of the loop expression if the `break` statement is executed) in `loop` loops, but not `for`, `while`, or `while let` loops.Make sure `break value;` statements only occur in `loop` loops: let result = loop { // ok!if satisfied(i) {break 2*i;}i += 1; };

    ?您也可以通過Rust Compiler Error Index閱讀相同的解釋 。例如,要檢查E0571錯誤的解釋,您可以使用https://doc.rust-lang.org/error-index.html#E0571

    Panicking

    panic!()

    ? 在某些情況下,當發(fā)生錯誤時,我們無法做任何事情來處理它,如果錯誤是某種情況,那就不應該發(fā)生。換句話說,如果這是一個不可恢復的錯誤。

    ? 當我們不使用功能豐富的調試器或正確的日志時,有時我們需要通過打印特定的消息或變量綁定的值從特定的代碼行退出程序來調試代碼以了解當前的程序的流程。

    對于上述情況,我們可以使用panic!宏。讓我們看幾個例子。

    ? panic!() 運行基于線程。一個線程可能會被恐慌,而其他線程正在運行。

    01.從特定行退出。

    fn main() {// some code// if we need to debug in herepanic!(); }// -------------- Compile time error -------------- thread 'main' panicked at 'explicit panic', src/main.rs:5:5

    02.退出并顯示自定義錯誤消息。

    #[allow(unused_mut)] // ? A lint attribute used to suppress the warning; username variable does not need to be mutable fn main() {let mut username = String::new();// some code to get the nameif username.is_empty() {panic!("Username is empty!");}println!("{}", username); }// -------------- Compile time error -------------- thread 'main' panicked at 'Username is empty!', src/main.rs:8:9

    03.退出附帶代碼元素的值。

    #[derive(Debug)] // ? A lint attribute which use to implement `std::fmt::Debug` to Color struct Color {r: u8,g: u8,b: u8, }#[allow(unreachable_code)] // ? A lint attribute used to suppress the warning; unreachable statement fn main() {let some_color: Color;// some code to get the color. exsome_color = Color {r: 255, g: 255, b: 0};// if we need to debug in herepanic!("{:?}", some_color);println!("The color = rgb({},{},{})",some_color.r, some_color.g, some_color.b); }// -------------- Compile time error -------------- thread 'main' panicked at 'Color { r: 255, g: 255, b: 0 }', src/main.rs:16:5

    正如您在上面的示例中所看到的,panic!()支持println!()類型樣式參數(shù) 。默認情況下,它會輸出錯誤消息,文件路徑以及發(fā)生錯誤的行號和列號。

    unimplemented!()

    如果您的代碼具有未完成的代碼段,則有一個標準化宏unimplemented!()來標記這些路徑。如果程序通過這些路徑運行,程序將panicked并返回"not yet implemented"的錯誤消息。

    // error messages with panic!() thread 'main' panicked at 'explicit panic', src/main.rs:6:5 thread 'main' panicked at 'Username is empty!', src/main.rs:9:9 thread 'main' panicked at 'Color { r: 255, g: 255, b: 0 }', src/main.rs:17:5// error messages with unimplemented!() thread 'main' panicked at 'not yet implemented', src/main.rs:6:5 thread 'main' panicked at 'not yet implemented: Username is empty!', src/main.rs:9:9 thread 'main' panicked at 'not yet implemented: Color { r: 255, g: 255, b: 0 }', src/main.rs:17:5

    unreachable!()

    這是標記程序不應輸入的路徑的標準宏。如果程序進入這些路徑,程序將panicked并返回"'internal error: entered unreachable code'"錯誤消息。

    fn main() {let level = 22;let stage = match level {1...5 => "beginner",6...10 => "intermediate",11...20 => "expert",_ => unreachable!(),};println!("{}", stage); }// -------------- Compile time error -------------- thread 'main' panicked at 'internal error: entered unreachable code', src/main.rs:7:20

    我們也可以為此設置自定義錯誤消息。

    // --- with a custom message --- _ => unreachable!("Custom message"), // -------------- Compile time error -------------- thread 'main' panicked at 'internal error: entered unreachable code: Custom message', src/main.rs:7:20// --- with debug data --- _ => unreachable!("level is {}", level), // -------------- Compile time error -------------- thread 'main' panicked at 'internal error: entered unreachable code: level is 22', src/main.rs:7:14

    assert!(), assert_eq!(), assert_ne!()

    這些是標準宏,通常與測試斷言一起使用。

    • assert!()確保布爾表達式為true。如果表達式為false,則會發(fā)生panics。
    fn main() {let f = false;assert!(f) }// -------------- Compile time error -------------- thread 'main' panicked at 'assertion failed: f', src/main.rs:4:5
    • assert_eq!()確保兩個表達式相等。如果表達式不相等則會發(fā)生panics。
    fn main() {let a = 10;let b = 20;assert_eq!(a, b); }// -------------- Compile time error -------------- thread 'main' panicked at 'assertion failed: `(left == right)`left: `10`,right: `20`', src/main.rs:5:5
    • assert_ne!()確保兩個表達式不相等。如果表達式相等,它會發(fā)生panics。
    fn main() {let a = 10;let b = 10;assert_ne!(a, b); }// -------------- Compile time error -------------- thread 'main' panicked at 'assertion failed: `(left != right)`left: `10`,right: `10`', src/main.rs:5:5 ?使用表達式assert_ne!()和assert_eq!()應返回相同的數(shù)據(jù)類型。

    我們也可以為這些宏設置自定義錯誤消息。舉些例子,

  • 帶有自定義消息 assert_eq!()
  • fn main() {let a = 10;let b = 20;assert_eq!(a, b, "a and b should be equal"); }// -------------- Compile time error -------------- thread 'main' panicked at 'assertion failed: `(left == right)`left: `10`,right: `20`: a and b should be equal', src/main.rs:5:5
  • assert_eq!()帶有調試數(shù)據(jù)
  • fn main() {let a = 10;let b = 20;let c = 40;assert_eq!(a+b, c, "a = {} ; b = {}", a, b); }// -------------- Compile time error -------------- thread 'main' panicked at 'assertion failed: `(left == right)`left: `30`,right: `40`: a = 10 ; b = 20', src/main.rs:7:5

    debug_assert!(), debug_assert_eq!(), debug_assert_ne!()

    ?這些與上面的assert宏類似。但默認情況下,這些語句僅在非優(yōu)化構建中啟用。debug_assert除非我們傳遞-C debug-assertions給編譯器,否則在發(fā)布版本中將省略所有這些宏。

    Option and Result

    許多語言使用null\ nil\ undefined 類型來表示空輸出和Exceptions處理錯誤。Rust會同時使用兩者,特別是為了防止諸如空指針異常,異常等敏感數(shù)據(jù)泄漏等問題。相反,Rust提供了兩個特殊的通用枚舉 ; Option和Result處理上述案件。

    如您所知:

    ? Option可以包含某個值Some或沒有值/ None。

    ? Result可以表示成功/ Ok 或失敗/Err。

    // An output can have either Some value or no value/ None. enum Option<T> { // T is a generic and it can contain any type of value.Some(T),None, }// A result can represent either success/ Ok or failure/ Err. enum Result<T, E> { // T and E are generics. T can contain any type of value, E can be any error.Ok(T),Err(E), }

    Option的基本用法

    編寫函數(shù)或數(shù)據(jù)類型時:

    • 如果函數(shù)的參數(shù)是可選的,
    • 如果函數(shù)為非空,并且返回的輸出可以為空,
    • 如果數(shù)據(jù)類型的屬性的值可以是空,我們不得不使用他們的數(shù)據(jù)類型為Option類型

    例如,如果函數(shù)輸出一個&str值并且輸出可以為空,則函數(shù)的返回類型應設置為Option<&str>

    fn get_an_optional_value() -> Option<&str> {//if the optional value is not emptyreturn Some("Some value");//elseNone }

    同樣,如果數(shù)據(jù)類型的屬性值可以為空或者像下面示例中middle_name的Name數(shù)據(jù)類型那樣可選,我們應該將其數(shù)據(jù)類型設置為Option類型。

    struct Name {first_name: String,middle_name: Option<String>, // middle_name can be emptylast_name: String, }

    ?如您所知,我們可以使用模式匹配match來捕獲相關的返回類型(Some/ None) 。有一個函數(shù)來獲取當前用戶的主目錄在std::env為home_dir() 。由于所有用戶在Linux等系統(tǒng)中都沒有主目錄,因此用戶的主目錄可以是可選的。所以它返回一個Option類型; Option<PathBuf>.

    use std::env;fn main() {let home_path = env::home_dir();match home_path {Some(p) => println!("{:?}", p), // This prints "/root", if you run this in Rust playgroundNone => println!("Can not find the home directory!"),} }

    ?但是,當在函數(shù)中使用可選參數(shù)時,我們必須None在調用函數(shù)時傳遞空參數(shù)的值。

    fn get_full_name(fname: &str, lname: &str, mname: Option<&str>) -> String { // middle name can be emptymatch mname {Some(n) => format!("{} {} {}", fname, n, lname),None => format!("{} {}", fname, lname),} }fn main() {println!("{}", get_full_name("Galileo", "Galilei", None));println!("{}", get_full_name("Leonardo", "Vinci", Some("Da"))); }// ? Better create a struct as Person with fname, lname, mname fields and create a impl function as full_name() ?除此之外,Option類型與Rust中的可空指針一起使用。由于Rust中沒有空指針,因此指針類型應指向有效位置。因此,如果指針可以為空,我們就可以使用了Option<Box<T>> 。

    Result的基本用法

    如果函數(shù)可以產生錯誤,我們必須Result通過組合有效輸出的數(shù)據(jù)類型和錯誤的數(shù)據(jù)類型來使用類型。例如,如果有效輸出的數(shù)據(jù)類型為u64且錯誤類型為String ,則返回類型應為Result<u64, String> 。

    fn function_with_error() -> Result<u64, String> {//if error happensreturn Err("The error message".to_string());// else, return valid outputOk(255) }

    ?如您所知,我們可以使用模式匹配match來捕獲相關的返回類型(Ok/ Err)。有一個函數(shù)可以獲取std::env 任何環(huán)境變量中的值是var() 。它的輸入是環(huán)境變量名稱。如果我們傳遞了錯誤的環(huán)境變量,或者程序在運行時無法提取環(huán)境變量的值,則會產生錯誤。所以它的返回類型是一種Result類型; Result<String, VarError>.

    use std::env;fn main() {let key = "HOME";match env::var(key) {Ok(v) => println!("{}", v), // This prints "/root", if you run this in Rust playgroundErr(e) => println!("{}", e), // This prints "environment variable not found", if you give a nonexistent environment variable} }

    is_some(), is_none(), is_ok(), is_err()

    除了match表情,rust還提供is_some() ,is_none()并且is_ok() ,is_err()功能,以確定返回類型。

    fn main() {let x: Option<&str> = Some("Hello, world!");assert_eq!(x.is_some(), true);assert_eq!(x.is_none(), false);let y: Result<i8, &str> = Ok(10);assert_eq!(y.is_ok(), true);assert_eq!(y.is_err(), false); }

    ok(), err() for Result types

    rust另外提供ok()和err()為Result類型。它們將Result類型的Ok<T>值和Err<E>值轉換為Option類型。

    fn main() {let o: Result<i8, &str> = Ok(8);let e: Result<i8, &str> = Err("message");assert_eq!(o.ok(), Some(8)); // Ok(v) ok = Some(v)assert_eq!(e.ok(), None); // Err(v) ok = Noneassert_eq!(o.err(), None); // Ok(v) err = Noneassert_eq!(e.err(), Some("message")); // Err(v) err = Some(v) }

    Unwrap and Expect

    unwrap()

    ?如果Option類型具有Some值或Result類型具有Ok值,則其中的值將傳遞到下一步。

    ?如果Option類型具有None值或Result類型具有Err值,則編程panics ; 如果Err,panics攜帶錯誤消息。

    該功能與以下代碼類似,使用match而不是使用unwrap() 。

    示例使用Option和match

    fn main() {let x;match get_an_optional_value() {Some(v) => x = v, // if Some("abc"), set x to "abc"None => panic!(), // if None, panic without any message}println!("{}", x); // "abc" ; if you change line 14 `false` to `true` }fn get_an_optional_value() -> Option<&'static str> {//if the optional value is not emptyif false {return Some("abc");}//elseNone }// --------------- Compile time error --------------- thread 'main' panicked at 'explicit panic', src/main.rs:5:17

    示例使用Result和match

    fn main() {let x;match function_with_error() {Ok(v) => x = v, // if Ok(255), set x to 255Err(e) => panic!(e), // if Err("some message"), panic with error message "some message"}println!("{}", x); // 255 ; if you change line 13 `true` to `false` }fn function_with_error() -> Result<u64, String> {//if error happensif true {return Err("some message".to_string());}// else, return valid outputOk(255) }// ---------- Compile time error ---------- thread 'main' panicked at 'some message', src/main.rs:5:19

    上述main函數(shù)中的相同代碼可以使用unwrap()兩行來編寫。

    // 01. unwrap error message for None fn main() {let x = get_an_optional_value().unwrap();println!("{}", x); }// --------------- Compile time error --------------- thread 'main' panicked at 'called `Option::unwrap()` on a `None` value', libcore/option.rs:345:21// 02. unwrap error message for Err fn main() {let x = function_with_error().unwrap();println!("{}", x); }// --------------- Compile time error --------------- thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: "some message"', libcore/result.rs:945:5

    ?但是正如您所看到的,當使用unwrap()錯誤消息時,沒有顯示發(fā)生恐慌的確切行號。

    expect()

    類似unwrap()但可以為恐慌設置自定義消息。

    // 01. expect error message for None fn main() {let n: Option<i8> = None;n.expect("empty value returned"); }// --------------- Compile time error --------------- thread 'main' panicked at 'empty value returned', libcore/option.rs:989:5// 02. expect error message for Err fn main() {let e: Result<i8, &str> = Err("some message");e.expect("expect error message"); }// --------------- Compile time error --------------- thread 'main' panicked at 'expect error message: "some message"', libcore/result.rs:945:5

    unwrap_err() and expect_err() for Result types

    unwrap()和expect()相反的情況; Ok時恐慌而不是Err時。兩者都在Ok錯誤消息中打印內部值。

    ?通常用于測試。

    // 01. unwrap_err error message for Ok fn main() {let o: Result<i8, &str> = Ok(8);o.unwrap_err(); }// ---------- Compile time error ---------- thread 'main' panicked at 'called `Result::unwrap_err()` on an `Ok` value: 8', libcore/result.rs:945:5// 02. expect_err error message for Ok fn main() {let o: Result<i8, &str> = Ok(8);o.expect_err("Should not get Ok value"); }// ---------- Compile time error ---------- thread 'main' panicked at 'Should not get Ok value: 8', libcore/result.rs:945:5

    unwrap_or(), unwrap_or_default() and unwrap_or_else()

    ?這些有點類似于unwrap(),如果Option類型有Some值或Result類型有Ok值,則它們內部的值傳遞到下一步。但是當有None 或者 Err,功能有點不同。
    • unwrap_or() :使用None或Err,您傳遞給的unwrap_or()值將傳遞到下一步。但是,您傳遞的值的數(shù)據(jù)類型應與相關Some或Ok的數(shù)據(jù)類型匹配。
    fn main() {let v1 = 8;let v2 = 16;let s_v1 = Some(8);let n = None;assert_eq!(s_v1.unwrap_or(v2), v1); // Some(v1) unwrap_or v2 = v1assert_eq!(n.unwrap_or(v2), v2); // None unwrap_or v2 = v2let o_v1: Result<i8, &str> = Ok(8);let e: Result<i8, &str> = Err("error");assert_eq!(o_v1.unwrap_or(v2), v1); // Ok(v1) unwrap_or v2 = v1assert_eq!(e.unwrap_or(v2), v2); // Err unwrap_or v2 = v2 }
    • unwrap_or_default() :使用None或Err,相關的數(shù)據(jù)類型的默認值Some或者Ok,傳遞到下一步。
    fn main() {let v = 8;let v_default = 0;let s_v: Option<i8> = Some(8);let n: Option<i8> = None;assert_eq!(s_v.unwrap_or_default(), v); // Some(v) unwrap_or_default = vassert_eq!(n.unwrap_or_default(), v_default); // None unwrap_or_default = default value of vlet o_v: Result<i8, &str> = Ok(8);let e: Result<i8, &str> = Err("error");assert_eq!(o_v.unwrap_or_default(), v); // Ok(v) unwrap_or_default = vassert_eq!(e.unwrap_or_default(), v_default); // Err unwrap_or_default = default value of v }
    • unwrap_or_else() :類似于unwrap_or()。唯一的區(qū)別是,您必須傳遞一個閉包,它返回一個具有Some或Ok相關數(shù)據(jù)類型的值,而不是傳遞一個值。
    fn main() {let v1 = 8;let v2 = 16;let s_v1 = Some(8);let n = None;let fn_v2_for_option = || 16;assert_eq!(s_v1.unwrap_or_else(fn_v2_for_option), v1); // Some(v1) unwrap_or_else fn_v2 = v1assert_eq!(n.unwrap_or_else(fn_v2_for_option), v2); // None unwrap_or_else fn_v2 = v2let o_v1: Result<i8, &str> = Ok(8);let e: Result<i8, &str> = Err("error");let fn_v2_for_result = |_| 16;assert_eq!(o_v1.unwrap_or_else(fn_v2_for_result), v1); // Ok(v1) unwrap_or_else fn_v2 = v1assert_eq!(e.unwrap_or_else(fn_v2_for_result), v2); // Err unwrap_or_else fn_v2 = v2 }

    Error and None Propagation

    我們應該使用恐慌panic!(),unwrap(),expect()只有當我們沒有一個更好處理辦法的情況。此外如果一個函數(shù)包含表達式既能產生None也能產生Err,

    ?我們可以在同一函數(shù)中處理

    ?我們可以立即返回None 和Err給調用者。因此調用者可以決定如何處理它們。

    ? None類型無需始終由函數(shù)的調用者處理。但Rusts處理Err類型的約定是,立即將它們返回給調用者,以便給調用者更多的控制權來決定如何處理它們。

    ?操作符

    ?如果Option類型具有Some值或Result類型具有Ok值,則其中的值將傳遞到下一步。
    ?如果Option類型具有None值或Result類型具有Err值,則立即將它們返回給函數(shù)的調用者。

    示例Option類型,

    fn main() {if complex_function().is_none() {println!("X not exists!");} }fn complex_function() -> Option<&'static str> {let x = get_an_optional_value()?; // if None, returns immidiately; if Some("abc"), set x to "abc"// some other code, exprintln!("{}", x); // "abc" ; if you change line 19 `false` to `true` Some("") }fn get_an_optional_value() -> Option<&'static str> {//if the optional value is not emptyif false {return Some("abc");}//elseNone }

    示例Result類型,

    fn main() {// `main` function is the caller of `complex_function` function// So we handle errors of complex_function(), inside main()if complex_function().is_err() {println!("Can not calculate X!");} }fn complex_function() -> Result<u64, String> {let x = function_with_error()?; // if Err, returns immidiately; if Ok(255), set x to 255// some other code, exprintln!("{}", x); // 255 ; if you change line 20 `true` to `false`Ok(0) }fn function_with_error() -> Result<u64, String> {//if error happensif true {return Err("some message".to_string());}// else, return valid outputOk(255) }

    從main()傳播錯誤

    在Rust版本1.26之前,我們無法從main()函數(shù)傳播Result和Option。但是現(xiàn)在,我們可以從main()函數(shù)中傳播Result類型,并打印出Err的Debug表示形式。

    use std::fs::File;fn main() -> std::io::Result<()> {let _ = File::open("not-existing-file.txt")?;Ok(()) // Because of the default return value of Rust functions is an empty tuple/ () }// Because of the program can not find not-existing-file.txt , it produces, // Err(Os { code: 2, kind: NotFound, message: "No such file or directory" }) // While propagating error, the program prints, // Error: Os { code: 2, kind: NotFound, message: "No such file or directory" }

    Combinators

    讓我們看看組合器是什么,

    • “組合者”的一個含義是更加非正式的意義,指的是組合模式,一種以組合事物的思想為中心組織圖書館的風格。通常存在一些類型T,一些用于構造類型T的“原始”值的函數(shù),以及一些可以以各種方式組合類型T的值以構建類型T的更復雜值的 “ 組合器 ” 。另一個定義是“ 沒有自由變量的函數(shù) ”(wiki.haskell.org)
    • 組合子是一個函數(shù),其從程序片段構建程序片段 ; 從某種意義上說,使用組合器的程序員自動構建了大部分所需的程序,而不是手工編寫每個細節(jié)。

    Rust生態(tài)系統(tǒng)中“組合子”的確切定義有點不清楚。

    ? or(),and(),or_else(),and_then()

    • 組合類型為T的兩個值并返回相同類型T。

    ? filter()對于Option類型

    • 使用閉包作為條件函數(shù)來過濾類型T.
    • 返回相同的類型T.

    ? map(),map_err()

    • 通過使用閉包轉換類型T。
    • 可以更改T內部值的數(shù)據(jù)類型。例如:Some<&str>可轉化為Some<usize>或者Err<&str>可轉化為Err<isize>等

    ? map_or(),map_or_else()

    • 通過應用閉包轉換類型T并返回類型T內的值。
    • 對None 和Err,應用默認值或其他閉包。

    ? ok_or(),ok_or_else()對于Option類型

    • 將Option類型轉換為Result類型。

    ? as_ref(),as_mut()

    • 將類型T轉換為引用或可變引用。

    or() and and()

    組合兩個表達式返回Option/ Result

    ?or() :如果任何一個得到Some或Ok`,該值立即返回。

    ? and() :如果兩者都得到Some或Ok,則返回第二個表達式中的值。如果任何一個獲得None或Err該值立即返回。

    fn main() {let s1 = Some("some1");let s2 = Some("some2");let n: Option<&str> = None;let o1: Result<&str, &str> = Ok("ok1");let o2: Result<&str, &str> = Ok("ok2");let e1: Result<&str, &str> = Err("error1");let e2: Result<&str, &str> = Err("error2");assert_eq!(s1.or(s2), s1); // Some1 or Some2 = Some1assert_eq!(s1.or(n), s1); // Some or None = Someassert_eq!(n.or(s1), s1); // None or Some = Someassert_eq!(n.or(n), n); // None1 or None2 = None2assert_eq!(o1.or(o2), o1); // Ok1 or Ok2 = Ok1assert_eq!(o1.or(e1), o1); // Ok or Err = Okassert_eq!(e1.or(o1), o1); // Err or Ok = Okassert_eq!(e1.or(e2), e2); // Err1 or Err2 = Err2assert_eq!(s1.and(s2), s2); // Some1 and Some2 = Some2assert_eq!(s1.and(n), n); // Some and None = Noneassert_eq!(n.and(s1), n); // None and Some = Noneassert_eq!(n.and(n), n); // None1 and None2 = None1assert_eq!(o1.and(o2), o2); // Ok1 and Ok2 = Ok2assert_eq!(o1.and(e1), e1); // Ok and Err = Errassert_eq!(e1.and(o1), e1); // Err and Ok = Errassert_eq!(e1.and(e2), e1); // Err1 and Err2 = Err1 } ?nightly支持Option類型的xor(),它返回Some當只有一個表達式返回Some,而不是兩個。

    or_else()

    類似于or()。唯一的區(qū)別是,第二個表達式應該是一個返回相同類型T 的閉包。

    fn main() {// or_else with Optionlet s1 = Some("some1");let s2 = Some("some2");let fn_some = || Some("some2"); // similar to: let fn_some = || -> Option<&str> { Some("some2") };let n: Option<&str> = None;let fn_none = || None;assert_eq!(s1.or_else(fn_some), s1); // Some1 or_else Some2 = Some1assert_eq!(s1.or_else(fn_none), s1); // Some or_else None = Someassert_eq!(n.or_else(fn_some), s2); // None or_else Some = Someassert_eq!(n.or_else(fn_none), None); // None1 or_else None2 = None2// or_else with Resultlet o1: Result<&str, &str> = Ok("ok1");let o2: Result<&str, &str> = Ok("ok2");let fn_ok = |_| Ok("ok2"); // similar to: let fn_ok = |_| -> Result<&str, &str> { Ok("ok2") };let e1: Result<&str, &str> = Err("error1");let e2: Result<&str, &str> = Err("error2");let fn_err = |_| Err("error2");assert_eq!(o1.or_else(fn_ok), o1); // Ok1 or_else Ok2 = Ok1assert_eq!(o1.or_else(fn_err), o1); // Ok or_else Err = Okassert_eq!(e1.or_else(fn_ok), o2); // Err or_else Ok = Okassert_eq!(e1.or_else(fn_err), e2); // Err1 or_else Err2 = Err2 }

    and_then()

    類似于and()。唯一的區(qū)別是,第二個表達式應該是一個返回相同類型T 的閉包。

    fn main() {// and_then with Optionlet s1 = Some("some1");let s2 = Some("some2");let fn_some = |_| Some("some2"); // similar to: let fn_some = |_| -> Option<&str> { Some("some2") };let n: Option<&str> = None;let fn_none = |_| None;assert_eq!(s1.and_then(fn_some), s2); // Some1 and_then Some2 = Some2assert_eq!(s1.and_then(fn_none), n); // Some and_then None = Noneassert_eq!(n.and_then(fn_some), n); // None and_then Some = Noneassert_eq!(n.and_then(fn_none), n); // None1 and_then None2 = None1// and_then with Resultlet o1: Result<&str, &str> = Ok("ok1");let o2: Result<&str, &str> = Ok("ok2");let fn_ok = |_| Ok("ok2"); // similar to: let fn_ok = |_| -> Result<&str, &str> { Ok("ok2") };let e1: Result<&str, &str> = Err("error1");let e2: Result<&str, &str> = Err("error2");let fn_err = |_| Err("error2");assert_eq!(o1.and_then(fn_ok), o2); // Ok1 and_then Ok2 = Ok2assert_eq!(o1.and_then(fn_err), e2); // Ok and_then Err = Errassert_eq!(e1.and_then(fn_ok), e1); // Err and_then Ok = Errassert_eq!(e1.and_then(fn_err), e1); // Err1 and_then Err2 = Err1 }

    filter()

    ?通常在編程語言中,filter函數(shù)與數(shù)組或迭代器一起使用,通過函數(shù)/閉包過濾自己的元素來創(chuàng)建新的數(shù)組/迭代器。Rust還提供了一個filter()迭代器適配器,用于在迭代器的每個元素上應用閉包,將其轉換為另一個迭代器。然而,在這里,我們正在談論filter()函數(shù)與Option類型。

    僅當我們傳遞一個Some值并且給定的閉包為它返回true時,返回相同的Some類型。如果None傳遞類型或閉包返回false,返回None。閉包使用Some里面的值作為參數(shù)。Rust仍然支持filter()只支持Option的類型。

    fn main() {let s1 = Some(3);let s2 = Some(6);let n = None;let fn_is_even = |x: &i8| x % 2 == 0;assert_eq!(s1.filter(fn_is_even), n); // Some(3) -> 3 is not even -> Noneassert_eq!(s2.filter(fn_is_even), s2); // Some(6) -> 6 is even -> Some(6)assert_eq!(n.filter(fn_is_even), n); // None -> no value -> None }

    map() and map_err()

    ?通常在編程語言中,map()函數(shù)與數(shù)組或迭代器一起使用,以在數(shù)組或迭代器的每個元素上應用閉包。Rust還提供了一個map()迭代器適配器,用于在迭代器的每個元素上應用閉包,將其轉換為另一個迭代器。但是在這里我們討論的是map()函數(shù)與Option和Result類型。
    • map() :通過應用閉包來轉換類型T. 可以根據(jù)閉包的返回類型更改Some或Ok塊數(shù)據(jù)類型。轉換Option<T>為Option<U> ,轉換Result<T, E>為Result<U, E>

    ? map(),僅僅 Some和Ok值改變。對Err內部值沒有影響(None根本不包含任何值)。

    fn main() {let s1 = Some("abcde");let s2 = Some(5);let n1: Option<&str> = None;let n2: Option<usize> = None;let o1: Result<&str, &str> = Ok("abcde");let o2: Result<usize, &str> = Ok(5);let e1: Result<&str, &str> = Err("abcde");let e2: Result<usize, &str> = Err("abcde");let fn_character_count = |s: &str| s.chars().count();assert_eq!(s1.map(fn_character_count), s2); // Some1 map = Some2assert_eq!(n1.map(fn_character_count), n2); // None1 map = None2assert_eq!(o1.map(fn_character_count), o2); // Ok1 map = Ok2assert_eq!(e1.map(fn_character_count), e2); // Err1 map = Err2 }
    • map_err()對于Result類型:Err塊的數(shù)據(jù)類型可以根據(jù)閉包的返回類型進行更改。轉換Result<T, E>為Result<T, F>。

    ?map_err(),只有Err值會發(fā)生變化。對Ok內部的值沒有影響。

    fn main() {let o1: Result<&str, &str> = Ok("abcde");let o2: Result<&str, isize> = Ok("abcde");let e1: Result<&str, &str> = Err("404");let e2: Result<&str, isize> = Err(404);let fn_character_count = |s: &str| -> isize { s.parse().unwrap() }; // convert str to isizeassert_eq!(o1.map_err(fn_character_count), o2); // Ok1 map = Ok2assert_eq!(e1.map_err(fn_character_count), e2); // Err1 map = Err2 }

    map_or() and map_or_else()

    這些功能也與unwrap_or()和unwrap_or_else()相似。但是map_or()和map_or_else()在Some,Ok值上應用閉包和返回類型T內的值。

    • map_or() :僅支持Option類型(不支持Result)。將閉包應用于Some內部值并根據(jù)閉包返回輸出。為None類型返回給定的默認值。
    fn main() {const V_DEFAULT: i8 = 1;let s = Some(10);let n: Option<i8> = None;let fn_closure = |v: i8| v + 2;assert_eq!(s.map_or(V_DEFAULT, fn_closure), 12);assert_eq!(n.map_or(V_DEFAULT, fn_closure), V_DEFAULT); }
    • map_or_else() :支持兩種Option和Result類型(Result僅限nightly)。類似map_or()但應該提供另一個閉包而不是第一個參數(shù)的默認值。

    ? None類型不包含任何值。所以不需要將任何東西傳遞給閉包作為輸入Option類型。但是Err類型在其中包含一些值。因此,默認閉包應該能夠將其作為輸入讀取,同時將其與Result類型一起使用。

    #![feature(result_map_or_else)] // enable unstable library feature 'result_map_or_else' on nightly fn main() {let s = Some(10);let n: Option<i8> = None;let fn_closure = |v: i8| v + 2;let fn_default = || 1; // None doesn't contain any value. So no need to pass anything to closure as input.assert_eq!(s.map_or_else(fn_default, fn_closure), 12);assert_eq!(n.map_or_else(fn_default, fn_closure), 1);let o = Ok(10);let e = Err(5);let fn_default_for_result = |v: i8| v + 1; // Err contain some value inside it. So default closure should able to read it as inputassert_eq!(o.map_or_else(fn_default_for_result, fn_closure), 12);assert_eq!(e.map_or_else(fn_default_for_result, fn_closure), 6); }

    ok_or() and ok_or_else()

    如前所述ok_or(),ok_or_else()將Option類型轉換為Result類型。Some對Ok和None對Err 。

    • ok_or() :默認Err消息應作為參數(shù)傳遞.
    fn main() {const ERR_DEFAULT: &str = "error message";let s = Some("abcde");let n: Option<&str> = None;let o: Result<&str, &str> = Ok("abcde");let e: Result<&str, &str> = Err(ERR_DEFAULT);assert_eq!(s.ok_or(ERR_DEFAULT), o); // Some(T) -> Ok(T)assert_eq!(n.ok_or(ERR_DEFAULT), e); // None -> Err(default) }
    • ok_or_else() :類似于ok_or()。應該將閉包作為參數(shù)傳遞。
    fn main() {let s = Some("abcde");let n: Option<&str> = None;let fn_err_message = || "error message";let o: Result<&str, &str> = Ok("abcde");let e: Result<&str, &str> = Err("error message");assert_eq!(s.ok_or_else(fn_err_message), o); // Some(T) -> Ok(T)assert_eq!(n.ok_or_else(fn_err_message), e); // None -> Err(default) }

    as_ref() and as_mut()

    ?如前所述,這些函數(shù)用于借用類型T作為引用或作為可變引用。

    • as_ref() :轉換Option<T>到Option<&T>和Result<T, E>到Result<&T, &E>
    • as_mut() :轉換Option<T>到Option<&mut T>和Result<T, E>到Result<&mut T, &mut E>

    自定義錯誤類型

    Rust允許我們創(chuàng)建自己的Err類型。我們稱之為“ 自定義錯誤類型”。

    Error trait

    如您所知,traits定義了類型必須提供的功能。但是我們不需要總是為常用功能定義新的特性,因為Rust 標準庫提供了一些可以在我們自己的類型上實現(xiàn)的可重用特性。創(chuàng)建自定義錯誤類型時,std::error::Error trait可幫助我們將任何類型轉換為Err類型。

    use std::fmt::{Debug, Display};pub trait Error: Debug + Display {fn source(&self) -> Option<&(Error + 'static)> { ... } }

    一個特質可以從另一個特質繼承。trait Error: Debug + Display意味著Error特質繼承fmt::Debug和fmt::Display特質。

    // traits inside Rust standard library core fmt module/ std::fmt pub trait Display {fn fmt(&self, f: &mut Formatter) -> Result<(), Error>; }pub trait Debug {fn fmt(&self, f: &mut Formatter) -> Result<(), Error>; }

    ? Display

    • 最終用戶應如何將此錯誤視為面向消息/面向用戶的輸出。
    • 通常通過println!("{}")或打印eprintln!("{}")

    ? Debug

    • 如何顯示Errwhile調試/面向程序員的輸出。
    • 通常打印println!("{:?}")或eprintln!("{:?}")
      • 漂亮打印,可以使用println!("{:#?}")或eprintln!("{:#?}")。

    ? source()

    • 此錯誤的較低級別來源(如果有)。
    • 可選的。

    首先,讓我們看看如何std::error::Error在最簡單的自定義錯誤類型上實現(xiàn)特征。

    use std::fmt;// Custom error type; can be any type which defined in the current crate // ? In here, we use a simple "unit struct" to simplify the example struct AppError;// Implement std::fmt::Display for AppError impl fmt::Display for AppError {fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {write!(f, "An Error Occurred, Please Try Again!") // user-facing output} }// Implement std::fmt::Debug for AppError impl fmt::Debug for AppError {fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {write!(f, "{{ file: {}, line: {} }}", file!(), line!()) // programmer-facing output} }// A sample function to produce an AppError Err fn produce_error() -> Result<(), AppError> {Err(AppError) }fn main() {match produce_error() {Err(e) => eprintln!("{}", e), // An Error Occurred, Please Try Again!_ => println!("No error"),}eprintln!("{:?}", produce_error()); // Err({ file: src/main.rs, line: 17 }) }

    希望你理解要點。現(xiàn)在,讓我們看一些帶有錯誤代碼和錯誤消息的自定義錯誤類型。

    use std::fmt;struct AppError {code: usize,message: String, }// Different error messages according to AppError.code impl fmt::Display for AppError {fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {let err_msg = match self.code {404 => "Sorry, Can not find the Page!",_ => "Sorry, something is wrong! Please Try Again!",};write!(f, "{}", err_msg)} }// A unique format for dubugging output impl fmt::Debug for AppError {fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {write!(f,"AppError {{ code: {}, message: {} }}",self.code, self.message)} }fn produce_error() -> Result<(), AppError> {Err(AppError {code: 404,message: String::from("Page not found"),}) }fn main() {match produce_error() {Err(e) => eprintln!("{}", e), // Sorry, Can not find the Page!_ => println!("No error"),}eprintln!("{:?}", produce_error()); // Err(AppError { code: 404, message: Page not found })eprintln!("{:#?}", produce_error());// Err(// AppError { code: 404, message: Page not found }// ) }

    ??Rust標準庫不僅提供了可重用的特性,而且還有助于通過#[derive]屬性神奇地生成少數(shù)特征的實現(xiàn)。Rust支持derive std::fmt::Debug,為調試消息提供默認格式。因此,我們可以在struct前聲明使用#[derive(Debug)]跳過實現(xiàn)std::fmt::Debug 自定義錯誤類型。

    use std::fmt;#[derive(Debug)] // derive std::fmt::Debug on AppError struct AppError {code: usize,message: String, }impl fmt::Display for AppError {fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {let err_msg = match self.code {404 => "Sorry, Can not find the Page!",_ => "Sorry, something is wrong! Please Try Again!",};write!(f, "{}", err_msg)} }fn produce_error() -> Result<(), AppError> {Err(AppError {code: 404,message: String::from("Page not found"),}) }fn main() {match produce_error() {Err(e) => eprintln!("{}", e), // Sorry, Can not find the Page!_ => println!("No error"),}eprintln!("{:?}", produce_error()); // Err(AppError { code: 404, message: Page not found })eprintln!("{:#?}", produce_error());// Err(// AppError {// code: 404,// message: "Page not found"// }// ) }

    From trait

    在編寫真實的程序時,我們大多數(shù)時候必須同時處理不同的模塊,不同的std和第三方的板條箱。但是每個包都使用自己的錯誤類型,如果我們使用自己的錯誤類型,我們應該將這些錯誤轉換為錯誤類型。我們可以使用std::convert::From標準化特征進行這些轉換。

    // traits inside Rust standard library core convert module/ std::convert pub trait From<T>: Sized {fn from(_: T) -> Self; } ?如您所知,String::from()函數(shù)用于創(chuàng)建String from &str數(shù)據(jù)類型。實際上這也是std::convert::From特質的實現(xiàn)。

    讓我們看看如何在自定義錯誤類型上實現(xiàn)std::convert::From特征。

    use std::fs::File; use std::io;#[derive(Debug)] struct AppError {kind: String, // type of the errormessage: String, // error message }// Implement std::convert::From for AppError; from io::Error impl From<io::Error> for AppError {fn from(error: io::Error) -> Self {AppError {kind: String::from("io"),message: error.to_string(),}} }fn main() -> Result<(), AppError> {let _file = File::open("nonexistent_file.txt")?; // This generates an io::Error. But because of return type is Result<(), AppError>, it converts to AppErrorOk(()) }// --------------- Run time error --------------- Error: AppError { kind: "io", message: "No such file or directory (os error 2)" }

    在上面的例子中,File::open(“nonexistent.txt”)?產生std::io::Error。但由于返回類型是Result<(), AppError>,它轉換為AppError。因為我們正在從main()函數(shù)傳播錯誤,所以它會打印出Err的Debug表示形式。

    在上面的例子中,我們只處理一種std錯誤類型std::io::Error。讓我們看一些處理多種std錯誤類型的例子。

    use std::fs::File; use std::io::{self, Read}; use std::num;#[derive(Debug)] struct AppError {kind: String,message: String, }// Implement std::convert::From for AppError; from io::Error impl From<io::Error> for AppError {fn from(error: io::Error) -> Self {AppError {kind: String::from("io"),message: error.to_string(),}} }// Implement std::convert::From for AppError; from num::ParseIntError impl From<num::ParseIntError> for AppError {fn from(error: num::ParseIntError) -> Self {AppError {kind: String::from("parse"),message: error.to_string(),}} }fn main() -> Result<(), AppError> {let mut file = File::open("hello_world.txt")?; // generates an io::Error, if can not open the file and converts to an AppErrorlet mut content = String::new();file.read_to_string(&mut content)?; // generates an io::Error, if can not read file content and converts to an AppErrorlet _number: usize;_number = content.parse()?; // generates num::ParseIntError, if can not convert file content to usize and converts to an AppErrorOk(()) }// --------------- Few possible run time errors ---------------// 01. If hello_world.txt is a nonexistent file Error: AppError { kind: "io", message: "No such file or directory (os error 2)" }// 02. If user doesn't have relevant permission to access hello_world.txt Error: AppError { kind: "io", message: "Permission denied (os error 13)" }// 03. If hello_world.txt contains non-numeric content. ex Hello, world! Error: AppError { kind: "parse", message: "invalid digit found in string" } ? 搜索有關實現(xiàn)的內容std::io::ErrorKind,以了解如何進一步組織錯誤類型。

    總結

    以上是生活随笔為你收集整理的Rust错误处理的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內容還不錯,歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 国产丰满大乳奶水在线视频 | 久久久青青草 | 亚洲一区二区三区在线视频观看 | 久久久77| 亚洲三级网| 久久国产影院 | 精品国产一级 | 亚洲精品乱码久久久久久蜜桃图片 | 亚洲久操| 亚洲二区在线观看 | 国产美女免费 | 91成人观看 | 波多野结衣一区二区三区在线观看 | 精品一区二区免费视频 | 欧美精品一卡二卡 | 久久aaa| 激情综 | 久久久久久国产视频 | 国产51页 | 日本精品入口免费视频 | 蜜桃无码一区二区三区 | 日韩欧美不卡 | 强侵犯の奶水授乳羞羞漫虐 | av免费视屏 | 亚洲AV不卡无码一区二区三区 | 99热这里只有精品在线观看 | 北条麻妃久久 | 天堂av中文字幕 | 岛国二区三区 | 青青在线视频 | 成人国产片 | 香蕉视频一级片 | 国产无遮挡免费观看视频网站 | 日本天堂在线视频 | www.亚洲免费 | 亚洲毛片精品 | 人妻互换一二三区激情视频 | 欧美精品乱码久久久久久按摩 | 日本少妇三级 | 上海贵妇尝试黑人洋吊 | 国产 日韩 欧美在线 | 毛片福利视频 | 我看黄色一级片 | 日日摸夜夜添狠狠添欧美 | 中文字幕亚洲欧美日韩 | 淫久久 | 激情综合五月婷婷 | 成人爱爱免费视频 | 色七七桃花综合影院 | 亚洲激情欧美色图 | 大乳女喂男人吃奶视频 | 国产精品视频免费网站 | 久久久久亚洲AV成人网人人小说 | 色操插| 4438五月天| 精品96久久久久久中文字幕无 | 古代黄色一级片 | 日本不卡一区二区在线观看 | 亚洲成人tv| 亚洲一级特黄毛片 | 60分钟| 日本a级c片免费看三区 | 精品视频一区二区三区四区五区 | 日韩免费av一区 | 日韩中出 | 国产美女网站视频 | 亚洲欧美日韩一区二区 | 春色影视 | 亚洲影视一区二区 | 久久偷看各类wc女厕嘘嘘偷窃 | 99999视频| 久久久欧美 | 日本高清黄色电影 | 成人羞羞国产免费游戏 | 精品人伦一区二区三区蜜桃免费 | 一区二区视频播放 | av 日韩 人妻 黑人 综合 无码 | 天堂在线播放 | 尤物视频在线看 | 国产高清自拍视频 | 97色涩| 黄色一级在线视频 | 国产精品第13页 | 久一视频在线观看 | av免费观看网 | 狠狠狠狠狠 | 国产做爰xxxⅹ久久久精华液 | 欧美精品一级二级三级 | 欧美毛片基地 | 91网站在线观看视频 | 成人一区二区在线 | 激情综合色 | av网址在线看| 日日摸夜夜添夜夜 | 94av| 一区二区三区精品 | 就爱啪啪网 | 日韩视频三区 | 激情综合网站 |