Rust Result 與可恢復的錯誤

Result 與可恢復的錯誤

大部分錯誤并沒有嚴重到需要程序完全停止執行。有時,一個函數會因為一個容易理解并做出反應的原因失敗。例如,如果因為打開一個并不存在的文件而失敗,此時我們可能想要創建這個文件,而不是終止進程。

回憶一下第 2 章 “使用 Result 類型來處理潛在的錯誤” 部分中的那個 Result 枚舉,它定義有如下兩個成員,OkErr

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

TE 是泛型類型參數;第 10 章會詳細介紹泛型。現在你需要知道的就是 T 代表成功時返回的 Ok 成員中的數據的類型,而 E 代表失敗時返回的 Err 成員中的錯誤的類型。因為 Result 有這些泛型類型參數,我們可以將 Result 類型和標準庫中為其定義的函數用于很多不同的場景,這些情況中需要返回的成功值和失敗值可能會各不相同。

讓我們調用一個返回 Result 的函數,因為它可能會失敗:如示例 9-3 所示打開一個文件:

文件名: src/main.rs

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

示例 9-3:打開文件

如何知道 File::open 返回一個 Result 呢?我們可以查看 標準庫 API 文檔 ,或者可以直接問編譯器!如果給 f 某個我們知道 不是 函數返回值類型的類型標注,接著嘗試編譯代碼,編譯器會告訴我們類型不匹配。然后錯誤信息會告訴我們 f 的類型 應該 是什么。讓我們試試!我們知道 File::open 的返回值不是 u32 類型的,所以將 let f 語句改為如下:

let f: u32 = File::open("hello.txt");

現在嘗試編譯會給出如下輸出:

error[E0308]: mismatched types--> src/main.rs:4:18|
4 |     let f: u32 = File::open("hello.txt");|                  ^^^^^^^^^^^^^^^^^^^^^^^ expected u32, found enum
`std::result::Result`|= note: expected type `u32`found type `std::result::Result<std::fs::File, std::io::Error>`

這就告訴我們了 File::open 函數的返回值類型是 Result<T, E>。這里泛型參數 T 放入了成功值的類型 std::fs::File,它是一個文件句柄。E 被用在失敗值上時 E 的類型是 std::io::Error

這個返回值類型說明 File::open 調用可能會成功并返回一個可以進行讀寫的文件句柄。這個函數也可能會失敗:例如,文件可能并不存在,或者可能沒有訪問文件的權限。File::open 需要一個方式告訴我們是成功還是失敗,并同時提供給我們文件句柄或錯誤信息。而這些信息正是 Result 枚舉可以提供的。

File::open 成功的情況下,變量 f 的值將會是一個包含文件句柄的 Ok 實例。在失敗的情況下,f 的值會是一個包含更多關于出現了何種錯誤信息的 Err 實例。

我們需要在示例 9-3 的代碼中增加根據 File::open 返回值進行不同處理的邏輯。示例 9-4 展示了一個使用基本工具(第 6 章學習過的 match 表達式)處理 Result 的例子:

文件名: src/main.rs

use std::fs::File;fn main() {let f = File::open("hello.txt");let f = match f {Ok(file) => file,Err(error) => {panic!("Problem opening the file: {:?}", error)},};
}

示例 9-4:使用 match 表達式處理可能會返回的 Result 成員

注意與 Option 枚舉一樣,Result 枚舉和其成員也被導入到了 prelude 中,所以就不需要在 match 分支中的 OkErr 之前指定 Result::

這里我們告訴 Rust 當結果是 Ok 時,返回 Ok 成員中的 file 值,然后將這個文件句柄賦值給變量 fmatch 之后,我們可以利用這個文件句柄來進行讀寫。

match 的另一個分支處理從 File::open 得到 Err 值的情況。在這種情況下,我們選擇調用 panic! 宏。如果當前目錄沒有一個叫做 hello.txt 的文件,當運行這段代碼時會看到如下來自 panic! 宏的輸出:

thread 'main' panicked at 'Problem opening the file: Error { repr:
Os { code: 2, message: "No such file or directory" } }', src/main.rs:9:12

一如既往,此輸出準確地告訴了我們到底出了什么錯。

匹配不同的錯誤

示例 9-4 中的代碼不管 File::open 是因為什么原因失敗都會 panic!。我們真正希望的是對不同的錯誤原因采取不同的行為:如果 File::open 因為文件不存在而失敗,我們希望創建這個文件并返回新文件的句柄。如果 File::open 因為任何其他原因失敗,例如沒有打開文件的權限,我們仍然希望像示例 9-4 那樣 panic!。讓我們看看示例 9-5,其中 match 增加了另一個分支:

文件名: src/main.rs

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

示例 9-5:使用不同的方式處理不同類型的錯誤

File::open 返回的 Err 成員中的值類型 io::Error,它是一個標準庫中提供的結構體。這個結構體有一個返回 io::ErrorKind 值的 kind 方法可供調用。io::ErrorKind 是一個標準庫提供的枚舉,它的成員對應 io 操作可能導致的不同錯誤類型。我們感興趣的成員是 ErrorKind::NotFound,它代表嘗試打開的文件并不存在。這樣,match 就匹配完 f 了,不過對于 error.kind() 還有一個內層 match

我們希望在內層 match 中檢查的條件是 error.kind() 的返回值是否為 ErrorKindNotFound 成員。如果是,則嘗試通過 File::create 創建文件。然而因為 File::create 也可能會失敗,還需要增加一個內層 match 語句。當文件不能被打開,會打印出一個不同的錯誤信息。外層 match 的最后一個分支保持不變,這樣對任何除了文件不存在的錯誤會使程序 panic。

這里有好多 matchmatch 確實很強大,不過也非常的基礎。第 13 章我們會介紹閉包(closure)。Result<T, E> 有很多接受閉包的方法,并采用 match 表達式實現。一個更老練的 Rustacean 可能會這么寫:

use std::fs::File;
use std::io::ErrorKind;fn main() {let f = File::open("hello.txt").unwrap_or_else(|error| {if error.kind() == ErrorKind::NotFound {File::create("hello.txt").unwrap_or_else(|error| {panic!("Problem creating the file: {:?}", error);})} else {panic!("Problem opening the file: {:?}", error);}});
}

雖然這段代碼有著如示例 9-5 一樣的行為,但并沒有包含任何 match 表達式且更容易閱讀。在閱讀完第 13 章后再回到這個例子,并查看標準庫文檔 unwrap_or_else 方法都做了什么操作。在處理錯誤時,還有很多這類方法可以消除大量嵌套的 match 表達式。

失敗時 panic 的簡寫:unwrapexpect

match 能夠勝任它的工作,不過它可能有點冗長并且不總是能很好地表明其意圖。Result<T, E> 類型定義了很多輔助方法來處理各種情況。其中之一叫做 unwrap,它的實現就類似于示例 9-4 中的 match 語句。如果 Result 值是成員 Okunwrap 會返回 Ok 中的值。如果 Result 是成員 Errunwrap 會為我們調用 panic!。這里是一個實踐 unwrap 的例子:

文件名: src/main.rs

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

如果調用這段代碼時不存在 hello.txt 文件,我們將會看到一個 unwrap 調用 panic! 時提供的錯誤信息:

thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Error {
repr: Os { code: 2, message: "No such file or directory" } }',
src/libcore/result.rs:906:4

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

文件名: src/main.rs

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

expectunwrap 的使用方式一樣:返回文件句柄或調用 panic! 宏。expect 在調用 panic! 時使用的錯誤信息將是我們傳遞給 expect 的參數,而不像 unwrap 那樣使用默認的 panic! 信息。它看起來像這樣:

thread 'main' panicked at 'Failed to open hello.txt: Error { repr: Os { code:
2, message: "No such file or directory" } }', src/libcore/result.rs:906:4

因為這個錯誤信息以我們指定的文本開始,Failed to open hello.txt,將會更容易找到代碼中的錯誤信息來自何處。如果在多處使用 unwrap,則需要花更多的時間來分析到底是哪一個 unwrap 造成了 panic,因為所有的 unwrap 調用都打印相同的信息。

傳播錯誤

當編寫一個需要先調用一些可能會失敗的操作的函數時,除了在這個函數中處理錯誤外,還可以選擇讓調用者知道這個錯誤并決定該如何處理。這被稱為 傳播propagating)錯誤,這樣能更好地控制代碼調用,因為比起你代碼所擁有的上下文,調用者可能擁有更多信息或邏輯來決定應該如何處理錯誤。

例如,示例 9-6 展示了一個從文件中讀取用戶名的函數。如果文件不存在或不能讀取,這個函數會將這些錯誤返回給調用它的代碼:

文件名: src/main.rs

use std::io;
use std::io::Read;
use std::fs::File;fn read_username_from_file() -> Result<String, io::Error> {let f = File::open("hello.txt");let mut f = match f {Ok(file) => file,Err(e) => return Err(e),};let mut s = String::new();match f.read_to_string(&mut s) {Ok(_) => Ok(s),Err(e) => Err(e),}
}

示例 9-6:一個函數使用 match 將錯誤返回給代碼調用者

首先讓我們看看函數的返回值:Result<String, io::Error>。這意味著函數返回一個 Result<T, E> 類型的值,其中泛型參數 T 的具體類型是 String,而 E 的具體類型是 io::Error。如果這個函數沒有出任何錯誤成功返回,函數的調用者會收到一個包含 StringOk 值 —— 函數從文件中讀取到的用戶名。如果函數遇到任何錯誤,函數的調用者會收到一個 Err 值,它儲存了一個包含更多這個問題相關信息的 io::Error 實例。這里選擇 io::Error 作為函數的返回值是因為它正好是函數體中那兩個可能會失敗的操作的錯誤返回值:File::open 函數和 read_to_string 方法。

函數體以 File::open 函數開頭。接著使用 match 處理返回值 Result,類似于示例 9-4 中的 match,唯一的區別是當 Err 時不再調用 panic!,而是提早返回并將 File::open 返回的錯誤值作為函數的錯誤返回值傳遞給調用者。如果 File::open 成功了,我們將文件句柄儲存在變量 f 中并繼續。

接著我們在變量 s 中創建了一個新 String 并調用文件句柄 fread_to_string 方法來將文件的內容讀取到 s 中。read_to_string 方法也返回一個 Result 因為它也可能會失敗:哪怕是 File::open 已經成功了。所以我們需要另一個 match 來處理這個 Result:如果 read_to_string 成功了,那么這個函數就成功了,并返回文件中的用戶名,它現在位于被封裝進 Oks 中。如果 read_to_string 失敗了,則像之前處理 File::open 的返回值的 match 那樣返回錯誤值。不過并不需要顯式的調用 return,因為這是函數的最后一個表達式。

調用這個函數的代碼最終會得到一個包含用戶名的 Ok 值,或者一個包含 io::ErrorErr 值。我們無從得知調用者會如何處理這些值。例如,如果他們得到了一個 Err 值,他們可能會選擇 panic! 并使程序崩潰、使用一個默認的用戶名或者從文件之外的地方尋找用戶名。我們沒有足夠的信息知曉調用者具體會如何嘗試,所以將所有的成功或失敗信息向上傳播,讓他們選擇合適的處理方法。

這種傳播錯誤的模式在 Rust 是如此的常見,以至于 Rust 提供了 ? 問號運算符來使其更易于處理。

傳播錯誤的簡寫:? 運算符

示例 9-7 展示了一個 read_username_from_file 的實現,它實現了與示例 9-6 中的代碼相同的功能,不過這個實現使用了 ? 運算符:

文件名: src/main.rs

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

示例 9-7:一個使用 ? 運算符向調用者返回錯誤的函數

Result 值之后的 ? 被定義為與示例 9-6 中定義的處理 Result 值的 match 表達式有著完全相同的工作方式。如果 Result 的值是 Ok,這個表達式將會返回 Ok 中的值而程序將繼續執行。如果值是 ErrErr 將作為整個函數的返回值,就好像使用了 return 關鍵字一樣,這樣錯誤值就被傳播給了調用者。

示例 9-6 中的 match 表達式與問號運算符所做的有一點不同:? 運算符所使用的錯誤值被傳遞給了 from 函數,它定義于標準庫的 From trait 中,其用來將錯誤從一種類型轉換為另一種類型。當 ? 運算符調用 from 函數時,收到的錯誤類型被轉換為由當前函數返回類型所指定的錯誤類型。這在當函數返回單個錯誤類型來代表所有可能失敗的方式時很有用,即使其可能會因很多種原因失敗。只要每一個錯誤類型都實現了 from 函數來定義如何將自身轉換為返回的錯誤類型,? 運算符會自動處理這些轉換。

在示例 9-7 的上下文中,File::open 調用結尾的 ? 將會把 Ok 中的值返回給變量 f。如果出現了錯誤,? 運算符會提早返回整個函數并將一些 Err 值傳播給調用者。同理也適用于 read_to_string 調用結尾的 ?

? 運算符消除了大量樣板代碼并使得函數的實現更簡單。我們甚至可以在 ? 之后直接使用鏈式方法調用來進一步縮短代碼,如示例 9-8 所示:

文件名: src/main.rs

use std::io;
use std::io::Read;
use std::fs::File;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)
}

示例 9-8:問號運算符之后的鏈式方法調用

s 中創建新的 String 被放到了函數開頭;這一部分沒有變化。我們對 File::open("hello.txt")? 的結果直接鏈式調用了 read_to_string,而不再創建變量 f。仍然需要 read_to_string 調用結尾的 ?,而且當 File::openread_to_string 都成功沒有失敗時返回包含用戶名 sOk 值。其功能再一次與示例 9-6 和示例 9-7 保持一致,不過這是一個與眾不同且更符合工程學(ergonomic)的寫法。

說到編寫這個函數的不同方法,甚至還有一個更短的寫法:

文件名: src/main.rs

use std::io;
use std::fs;fn read_username_from_file() -> Result<String, io::Error> {fs::read_to_string("hello.txt")
}

示例 9-9: 使用 fs::read_to_string

將文件讀取到一個字符串是相當常見的操作,所以 Rust 提供了名為 fs::read_to_string 的函數,它會打開文件、新建一個 String、讀取文件的內容,并將內容放入 String,接著返回它。當然,這樣做就沒有展示所有這些錯誤處理的機會了,所以我們最初就選擇了艱苦的道路。

? 運算符可被用于返回 Result 的函數

? 運算符可被用于返回值類型為 Result 的函數,因為他被定義為與示例 9-6 中的 match 表達式有著完全相同的工作方式。matchreturn Err(e) 部分要求返回值類型是 Result,所以函數的返回值必須是 Result 才能與這個 return 相兼容。

讓我們看看在 main 函數中使用 ? 運算符會發生什么,如果你還記得的話其返回值類型是 ()

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

當編譯這些代碼,會得到如下錯誤信息:

error[E0277]: the `?` operator can only be used in a function that returns
`Result` or `Option` (or another type that implements `std::ops::Try`)--> src/main.rs:4:13|
4 |     let f = File::open("hello.txt")?;|             ^^^^^^^^^^^^^^^^^^^^^^^^ cannot use the `?` operator in afunction that returns `()`|= help: the trait `std::ops::Try` is not implemented for `()`= note: required by `std::ops::Try::from_error`

錯誤指出只能在返回 Result 或者其它實現了 std::ops::Try 的類型的函數中使用 ? 運算符。當你期望在不返回 Result 的函數中調用其他返回 Result 的函數時使用 ? 的話,有兩種方法修復這個問題。一種技巧是將函數返回值類型修改為 Result<T, E>,如果沒有其它限制阻止你這么做的話。另一種技巧是通過合適的方法使用 matchResult 的方法之一來處理 Result<T, E>

main 函數是特殊的,其必須返回什么類型是有限制的。main 函數的一個有效的返回值是 (),同時出于方便,另一個有效的返回值是 Result<T, E>,如下所示:

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

Box<dyn Error> 被稱為 “trait 對象”(trait object),第 17 章 “為使用不同類型的值而設計的 trait 對象” 部分會做介紹。目前可以理解 Box<dyn Error> 為使用 ?main 允許返回的 “任何類型的錯誤”。

現在我們討論過了調用 panic! 或返回 Result 的細節,是時候回到他們各自適合哪些場景的話題了。

推薦幾款學習編程的免費平臺

免費在線開發平臺(https://docs.ltpp.vip/LTPP/)

?????? 探索編程世界的新天地,為學生和開發者精心打造的編程平臺,現已盛大開啟!這個平臺匯集了近4000道精心設計的編程題目,覆蓋了C、C++、JavaScript、TypeScript、Go、Rust、PHP、Java、Ruby、Python3以及C#等眾多編程語言,為您的編程學習之旅提供了一個全面而豐富的實踐環境。 ??????
??????在這里,您不僅可以查看自己的代碼記錄,還能輕松地在云端保存和運行代碼,讓編程變得更加便捷。平臺還提供了私聊和群聊功能,讓您可以與同行們無障礙交流,分享文件,共同進步。不僅如此,您還可以通過閱讀文章、參與問答板塊和在線商店,進一步拓展您的知識邊界。
?????? 為了提升您的編程技能,平臺還設有每日一題、精選題單以及激動人心的編程競賽,這些都是備考編程考試的絕佳資源。更令人興奮的是,您還可以自定義系統UI,選擇視頻或圖片作為背景,打造一個完全個性化的編碼環境,讓您的編程之旅既有趣又充滿挑戰。

免費公益服務器(https://docs.ltpp.vip/LTPP-SHARE/linux.html)

?????? 作為開發者或學生,您是否經常因為搭建和維護編程環境而感到頭疼?現在,您不必再為此煩惱,因為一款全新的免費公共服務器已經為您解決了所有問題。這款服務器內置了多種編程語言的編程環境,并且配備了功能強大的在線版VS Code,讓您可以隨時隨地在線編寫代碼,無需進行任何復雜的配置。
隨時隨地,云端編碼
?????? 無論您身在何處,只要有網絡連接,就可以通過瀏覽器訪問這款公共服務器,開始您的編程之旅。這種云端編碼的便利性,讓您的學習或開發工作不再受限于特定的設備或環境。
豐富的編程語言支持
?????? 服務器支持包括C、C++、JavaScript、TypeScript、Go、Rust、PHP、Java、Ruby、Python3以及C#等在內的多種主流編程語言,滿足不同開發者和學生的需求。無論您是初學者還是資深開發者,都能找到適合自己的編程環境。
在線版VS Code,高效開發
?????? 內置的在線版VS Code提供了與本地VS Code相似的編輯體驗,包括代碼高亮、智能提示、代碼調試等功能,讓您即使在云端也能享受到高效的開發體驗。
數據隱私和安全提醒
?????? 雖然服務器是免費的,但為了保護您的數據隱私和安全,我們建議您不要上傳任何敏感或重要的數據。這款服務器更適合用于學習和實驗,而非存儲重要信息。

免費公益MYSQL(https://docs.ltpp.vip/LTPP-SHARE/mysql.html)

?????? 作為一名開發者或學生,數據庫環境的搭建和維護往往是一個復雜且耗時的過程。但不用擔心,現在有一款免費的MySQL服務器,專為解決您的煩惱而設計,讓數據庫的使用變得簡單而高效。
性能卓越,滿足需求
?????? 雖然它是免費的,但性能絕不打折。服務器提供了穩定且高效的數據庫服務,能夠滿足大多數開發和學習場景的需求。
在線phpMyAdmin,管理更便捷
?????? 內置的在線phpMyAdmin管理面板,提供了一個直觀且功能強大的用戶界面,讓您可以輕松地查看、編輯和管理數據庫。
數據隱私提醒,安全第一
?????? 正如您所知,這是一項公共資源,因此我們強烈建議不要上傳任何敏感或重要的數據。請將此服務器僅用于學習和實驗目的,以確保您的數據安全。

免費在線WEB代碼編輯器(https://docs.ltpp.vip/LTPP-WEB-IDE/)

?????? 無論你是開發者還是學生,編程環境的搭建和管理可能會占用你寶貴的時間和精力。現在,有一款強大的免費在線代碼編輯器,支持多種編程語言,讓您可以隨時隨地編寫和運行代碼,提升編程效率,專注于創意和開發。
多語言支持,無縫切換
?????? 這款在線代碼編輯器支持包括C、C++、JavaScript、TypeScript、Go、Rust、PHP、Java、Ruby、Python3以及C#在內的多種編程語言,無論您的項目需要哪種語言,都能在這里找到支持。
在線運行,快速定位問題
?????? 您可以在編寫代碼的同時,即時運行并查看結果,快速定位并解決問題,提高開發效率。
代碼高亮與智能提示
?????? 編輯器提供代碼高亮和智能提示功能,幫助您更快地編寫代碼,減少錯誤,提升編碼質量。

免費二維碼生成器(https://docs.ltpp.vip/LTPP-QRCODE/)

?????? 二維碼(QR Code)是一種二維條碼,能夠存儲更多信息,并且可以通過智能手機等設備快速掃描識別。它廣泛應用于各種場景,如:
企業宣傳
?????? 企業可以通過二維碼分享公司網站、產品信息、服務介紹等。
活動推廣
?????? 活動組織者可以創建二維碼,參與者掃描后可以直接訪問活動詳情、報名鏈接或獲取電子門票。
個人信息分享
?????? 個人可以生成包含聯系方式、社交媒體鏈接、個人簡歷等信息的二維碼。
電子商務
?????? 商家使用二維碼進行商品追蹤、促銷活動、在線支付等。
教育
?????? 教師可以創建二維碼,學生掃描后可以直接訪問學習資料或在線課程。
交通出行
?????? 二維碼用于公共交通的票務系統,乘客掃描二維碼即可進出站或支付車費。 ?????? 功能強大的二維碼生成器通常具備用戶界面友好,操作簡單,即使是初學者也能快速上手和生成的二維碼可以在各種設備和操作系統上掃描識別的特點。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:
http://www.pswp.cn/web/46368.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/46368.shtml
英文地址,請注明出處:http://en.pswp.cn/web/46368.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

RT-DETR+Flask實現目標檢測推理案例

今天&#xff0c;帶大家利用RT-DETR&#xff08;我們可以換成任意一個模型&#xff09;Flask來實現一個目標檢測平臺小案例&#xff0c;其實現效果如下&#xff1a; 目標檢測案例 這個案例很簡單&#xff0c;就是讓我們上傳一張圖像&#xff0c;隨后選擇一下置信度&#xff0c;…

GPT LangChain experimental agent - allow dangerous code

題意&#xff1a;GPT LangChain 實驗性代理 - 允許危險代碼 問題背景&#xff1a; Im creating a chatbot in VS Code where it will receive csv file through a prompt on Streamlit interface. However from the moment that file is loaded, it is showing a message with…

第12章 結構化命令《Linux命令行與Shell腳本編程大全筆記》

12.1 if-then命令 不同于其他語言&#xff0c;if后面不是一個等式&#xff0c;而是命令&#xff0c;如果命令運行成功返回狀態碼0則運行then語句部分把分號&#xff08;;&#xff09;放到命令尾部&#xff0c;可以將then語句寫在同一行 12.4 test命令 格式&#xff1a;if te…

激活pytorch遇到報錯usage: conda-script.py [-h] [--no-plugins] [-V] COMMAND ...

問題 今天初次嘗試在pycharm上創建與激活虛擬環境&#xff0c;創建結束后&#xff0c;使用命令conda activate pytorch激活虛擬環境時出現以下報錯&#xff1a; usage: conda-script.py [-h] [–no-plugins] [-V] COMMAND … conda-script.py: error: argument COMMAND: inval…

Selenium原理深度解析

在自動化測試領域&#xff0c;Selenium無疑是最受歡迎和廣泛使用的工具之一。它支持多種瀏覽器和操作系統&#xff0c;為開發人員和測試人員提供了強大的自動化測試解決方案。本文將深入探討Selenium的工作原理&#xff0c;包括其架構、核心組件、執行流程以及它在自動化測試中…

獨立開發者系列(26)——域名與解析

域名&#xff08;英語&#xff1a;Domain Name&#xff09;&#xff0c;又稱網域&#xff0c;是由一串用點分隔的名字組成的互聯網上某一臺計算機或計算機組的名稱&#xff0c;用于在數據傳輸時對計算機的定位標識&#xff08;有時也指地理位置&#xff09;。 由于IP地址不方便…

postMessageXss續2

原文地址如下:https://research.securitum.com/art-of-bug-bounty-a-way-from-js-file-analysis-to-xss/ 在19年我寫了一篇文章&#xff0c;是基于postMessageXss漏洞的入門教學:https://www.cnblogs.com/piaomiaohongchen/p/14727871.html 這幾天瀏覽mXss技術的時候&#xff…

模型蒸餾、量化、裁剪的概念和區別

模型壓縮概述 1.1 模型壓縮的重要性 隨著深度學習技術的快速發展&#xff0c;神經網絡模型在各種任務中取得了顯著的成功。然而&#xff0c;這些模型通常具有大量的參數和復雜的結構&#xff0c;導致模型體積龐大、計算資源消耗高和推理時間長。這些問題限制了深度學習模型在…

車載音視頻App框架設計

簡介 統一播放器提供媒體播放一致性的交互和視覺體驗&#xff0c;減少各個媒體應用和場景獨自開發的重復工作量&#xff0c;實現媒體播放鏈路的一致性&#xff0c;減少碎片化的Bug。本文面向應用開發者介紹如何快速接入媒體播放器。 主要功能&#xff1a; 新設計的統一播放U…

新版本cesium編譯1.103之后的版本

cesium1.1之后的版本文件結構域1.1之前的版本有了很大的差別&#xff0c;源碼也全部移到了packages目錄中。有很多依賴包沒有寫在根目錄的package.json文件中。npm i 后直接編譯會保持。 cesium源碼git https://github.com/CesiumGS/cesium 1、添加缺少的包&#xff0c;缺少的…

4. 雙端口ram設計

1. 設計要求 設計一個位寬8bit&#xff0c;地址深度為128&#xff0c;可以同時讀寫的雙端口RAM 要求&#xff1a;模塊名字為RAM_DUAL 輸入端口&#xff1a;ADDR_W&#xff0c;ADDR_R CLK_R&#xff0c;CLK_W&#xff0c;RSTn ADDR_R[6:0]&#xff0c;ADDR_W[6:0] DATA_WR…

k8s學習——創建測試鏡像

創建一個安裝了ifconfig、telnet、curl、nc、traceroute、ping、nslookup等網絡工具的鏡像&#xff0c;便于集群中的測試。 創建一個Dockerfile文件 # 使用代理下載 Ubuntu 鏡像作為基礎 FROM docker.m.daocloud.io/library/ubuntu:latest# 設置環境變量 DEBIAN_FRONTEND 為 …

學習測試9-接口測試 2-抓包工具Fiddler

Fiddler 抓包工具的使用 怎么找接口信息&#xff0c;可以通過瀏覽器的開發者工具 Fiddler 是一個 HTTP 協議調試代理工具 File 菜單&#xff1a; Capture Traffic&#xff08;或 F12&#xff09;&#xff1a;是個開關&#xff0c;可以控制是否把 Fiddler 注冊為系統代理。當把…

淺談Open.Json.pickle.Os

一、Open函數使用 open函數是 Python 中用于打開文件的內置函數&#xff0c;它返回一個文件對象&#xff0c;該文件對象提供了對文件進行讀寫操作的方法。使用 open 函數時&#xff0c;通常需要指定至少兩個參數&#xff1a;文件名&#xff08;file&#xff09;和模式&#xf…

【網絡工具】Charles 介紹及環境配置

?個人博客&#xff1a;Pandaconda-CSDN博客 &#x1f4e3;專欄地址&#xff1a;http://t.csdnimg.cn/iAmAo &#x1f4da;專欄簡介&#xff1a;在這個專欄中&#xff0c;我將會整理一些工作或學習中用到的工具介紹給大家~ &#x1f4d8;Charles 系列其它文章&#xff1a;【網絡…

Git操縱本地倉庫和遠程倉庫

git是一個代碼托管的平臺&#xff0c;我們可以對我們的代碼進行分支 推送提交 打標簽等等操作&#xff0c;而且git使用過程中也是支持一些linux語言的 比如cd呀 touch mkdir啊等等等 git的具體安裝過程就不再贅述 我個人認為 好多東西就是 代碼也好 文字 文檔 也好&…

【C語言】結構體,枚舉,聯合超詳解!!!

目錄 結構體 結構體聲明 結構體成員的訪問 結構體自引用 結構體變量定義&#xff0c;初始化&#xff0c;傳參 結構體內存對齊 位段 枚舉 聯合(共用體) 結構體 結構體聲明 1. 概念 1. 結構體是一些值的集合&#xff0c;這些值稱為成員變量。 2. 結構體的每個成員可…

長難句打卡7.15

The trend was naturally most obvious in those areas of science based especially on a mathematical or laboratory training, and can be illustrated in terms of the development of geology in the United Kingdom 這一趨勢自然在以數學或實驗室訓練為基礎的科學領域里…

Unlink

Unlink 原理 我們在利用 unlink 所造成的漏洞時&#xff0c;其實就是對 chunk 進行內存布局&#xff0c;然后借助 unlink 操作來達成修改指針的效果。簡單回顧一下 unlink 的目的與過程&#xff0c;其目的是把一個雙向鏈表中的空閑塊拿出來&#xff08;例如 free 時和目前物理…

Leetcode二分搜索法淺析

文章目錄 1.二分搜索法1.1什么是二分搜索法&#xff1f;1.2解法思路 1.二分搜索法 題目原文&#xff1a; 給定一個 n 個元素有序的&#xff08;升序&#xff09;整型數組 nums 和一個目標值 target &#xff0c;寫一個函數搜索 nums 中的 target&#xff0c;如果目標值存在返…