您好,登錄后才能下訂單哦!
本篇內容主要講解“Result/Option/unwrap/的概念是什么”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“Result/Option/unwrap/的概念是什么”吧!
雖然Rust中有null的概念,但是使用null并不是Rust中常見的模式。假設我們要寫一個函數,輸入一種手機操作系統的名稱,這個函數就會返回其應用商店的名稱。如果傳入字符串iOS
,該函數將返回App Store
;如果傳入字符串android
,那么該函數將返回Play Store。任何其他的輸入都被視為無效。
在大多數開發語言中,我們可以選擇返回null或字符串invalid
來表示無效的結果,不過這不是Rust的用法。
地道的Rust代碼應該讓該函數返回一個Option
。Option或更確切的說Option<T>
是一個泛型,可以是Some<T>
或None
(為了便于閱讀,后續文章中將省略類型參數T)。Rust將Some
和None
稱為變體(Variant) —— 這一概念在其他語言中并不存在,因此我也不 去定義到底什么是變體了。
在我們的示例中,正常情況下函數將返回包裹在Some變體中的字符串常量App Store或Play Store。而在非正常情況下,函數將返回None。
fn find_store(mobile_os: &str) -> Option<&str> { match mobile_os { "iOS" => Some("App Store"), "android" => Some("Play Store"), _ => None } }
要使用find_store(),我們可以用如下方式調用:
fn main() { println!("{}", match find_store("windows") { Some(s) => s, None => "Not a valid mobile OS" }); }
完整的代碼如下:
fn find_store(mobile_os: &str) -> Option<&str> { match mobile_os { "iOS" => Some("App Store"), "android" => Some("Play Store"), _ => None } } fn main() { println!("{}", match find_store("windows") { Some(s) => s, None => "Not a valid mobile OS" }); }
Result
,或者更確切地說Result<T,E>
,是和Rust中的Option相關的概念,它是一個加強版本的Option。
Result<T, E>可能有以下結果之一:
Ok(T):結果為成員T
Err(E):結果為故障成員E
與之前我們看到Option<T>可以包含Some<T>或None不同,Result中包含了錯誤相關信息,這是Option中所沒有的。
讓我們看一個函數實例,它返回一個Result。該函數摘自用于解析JSON字符串的serde_json庫,其簽名為:
pub fn from_str<'a, T>(s: &'a str) -> Result<T, Error> where T: Deserialize<'a>,
假設我們要解析如下的字符串:
let json_string = r#" { "name": "John Doe", "age": 43, "phones": [ "+44 1234567", "+44 2345678" ] }"#;
目標是解析為Rust的一個person結構對象:
#[derive(Serialize, Deserialize)] struct Person { name: String, age: u8, phones: Vec<String>, }
解析過程的Rust代碼如下:
let p:Person = match serde_json::from_str(json_string) { Ok(p) => p, Err(e) => ... //we will discuss what goes here next };
正常情況下可以得到期望的結果。不過假設在輸入的json_string中有一個筆誤,這導致程序運行時將執行Err分支。
當碰到Err時,我們可以采取兩個動作:
panic!
返回Err
在上面的示例中,假設我們期望panic!:
let p: Person = match serde_json::from_str(data) { Ok(p) => p, Err(e) => panic!("cannot parse JSON {:?}, e"), //panic }
當碰到Err時,上面的代碼panic!就會崩掉整個程序,也許這不是你期望的。我們可以修改為:
let p:Person = serde_json::from_str(data).unwrap();
如果我們可以確定輸入的json_string始終會是可解析的,那么使用unwrap沒有問題。但是如果會出現Err,那么程序就會崩潰,無法從故障中恢復。在開發過程中,當我們更關心程序的主流程時,unwrap也可以作為快速 原型使用。
因此unwrap隱含了panic!。雖然與更顯式的版本沒有差異,但是危險在于其隱含特性,因為有時這并不是你真正期望的行為。
無論如何,如果我們需要調用panic!,代碼如下:
use serde::{Deserialize, Serialize}; use serde_json::Result; #[derive(Serialize, Deserialize)] struct Person { name: String, age: u8, phones: Vec<String>, } fn typed_example() -> Result<()> { //age2 is error on purpose let data = r#" { "name": "John Doe", "age2": 43, "phones": [ "+44 1234567", "+44 2345678" ] }"#; let p:Person = serde_json::from_str(data).unwrap(); println!("Please call {} at the number {}", p.name, p.phones[0]); Ok(()) } fn main() { match typed_example() { Ok(_) => println!("program ran ok"), Err(_) => println!("program ran with error"), } }
當碰到Err時,我們不一定要panic!,也可以返回Err。不是每個Err都是不可恢復的,因此有時并不需要panic!。下面的代碼返回Err:
let p: Person = match serde_json::from_str(data) { Ok(p) => p, Err(e) => return Err(e.into()), };
?
操作符提供了一個更簡潔的方法來替換上面的代碼:
let p:Person = serde_json::from_str(data)?;
這時完整的Rust程序代碼如下:
use serde::{Deserialize, Serialize}; use serde_json::Result; #[derive(Serialize, Deserialize)] struct Person { name: String, age: u8, phones: Vec<String>, } fn typed_example() -> Result<()> { //age2 is error on purpose let data = r#" { "name": "John Doe", "age2": 43, "phones": [ "+44 1234567", "+44 2345678" ] }"#; let p: Person = serde_json::from_str(data)?; println!("Please call {} at the number {}", p.name, p.phones[0]); Ok(()) } fn main() { match typed_example() { Ok(_) => println!("program ran ok"), Err(e) => println!("program ran with error {:?}", e), } }
就像我們可以使用unwarp和?來處理Result,我們也可以使用unwrap和?來處理Option。
如果我們unwrap的Option的值是None,那么程序就會panic!。示例如下:
fn next_birthday(current_age: Option<u8>) -> Option<String> { // If `current_age` is `None`, this returns `None`. // If `current_age` is `Some`, the inner `u8` gets assigned to `next_age` after 1 is added to it let next_age: u8 = current_age?; Some(format!("Next year I will be {}", next_age + 1)) } fn main() { let s = next_birthday(None); match s { Some(a) => println!("{:#?}", a), None => println!("No next birthday") } }
到此,相信大家對“Result/Option/unwrap/的概念是什么”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。