2013-10-17 23 views
4

linuxfood has created bindings for sqlite3,對此我很感激。我剛開始學習拉斯特(0.8),和我想要了解什麼的這段代碼是這樣做的:這個Rust代碼可以在沒有「匹配」語句的情況下編寫嗎?

extern mod sqlite; 

fn db() { 

    let database = 
     match sqlite::open("test.db") { 
      Ok(db) => db, 
      Err(e) => { 
       println(fmt!("Error opening test.db: %?", e)); 
       return; 
      } 
     }; 

我明白基本上它做什麼。它試圖獲取數據庫連接並測試錯誤。我不明白這是怎麼回事。

爲了更好地理解它,我想在沒有match聲明的情況下重寫它,但我沒有這方面的知識。那可能嗎? sqlite::open()是否返回兩個變量,或者只有一個?

如果沒有match聲明,此示例的寫法有何不同?我並不是說這是必要的或者可取的,但它可以幫助我學習這門語言。

回答

6

外部語句是一個賦值,將匹配表達式的值賦值爲database。匹配表達式取決於sqlite::open的返回值,該值可能爲Result<T, E>(變體Ok(T)Err(E)爲enum)類型。在Ok的情況下,枚舉變量具有一個參數,匹配表達式將其解構爲db並返回該值(因此它將被分配給變量database)。如果它是Err,枚舉變量有一個帶有打印的錯誤對象的參數,函數返回。

,不使用匹配語句,這可以寫成這樣(只是因爲你明確要求不使用匹配 - 大多數人會認爲這種惡劣的編碼風格):

let res = sqlite::open("test.db"); 
if res.is_err() { 
    println!("Error opening test.db: {:?}", res.unwrap_err()); 
    return; 
} 
let database = res.unwrap(); 
+2

此代碼是我將如何回答這個問題。從這裏可以看到[Result struct]的定義(https://github.com/mozilla/rust/blob/master/src/libstd/result.rs#L33),然後[unwrap]( https://github.com/mozilla/rust/blob/master/src/libstd/result.rs#L108)方法。你可以看到'unwrap'使用'match',並且在一種情況下會導致'fail!'。這是_why_這被認爲是不好的風格:在運行時有潛在的失敗。 'match'的原因是編譯器確保你明確地處理每一個案例。 (編輯:修復SO標記。) – nejucomo

+0

感謝您的帖子。我不得不做下面的小改動來完成這個工作「println(fmt!(」Error open test.db:%?「,res));」。雖然我通常不會這樣編寫代碼,但它確實可以讓我更好地理解發生的事情。 –

+0

我不想聽起來迂腐,但「結果」實際上是一個枚舉,而不是一個結構。 ;)但是你說得對,Rust在Rust裏很棒。一方面它確保你不會意外地忘記處理一個案件,因爲匹配結構必須是詳盡的。另一方面,它提供解構來輕鬆訪問數據結構的內部組件。一個人通常不想避免但鼓勵使用'match'。 – Zargony

3

sqlite::open()正在返回一個枚舉。枚舉在生鏽方面有點不同,枚舉的每個值都可以包含字段。
參見http://static.rust-lang.org/doc/0.8/tutorial.html#enums

因此,在這種情況下,SqliteResult枚舉可以是OkErr如果它是Ok那麼它具有參考附屬於它的分貝,如果是Err然後它有錯誤的信息。

對於C#或Java背景,您可以將SqliteResult作爲基類,OkErr從中繼承,每個基類都有自己的相關信息。在這種情況下,match子句只是檢查類型以查看返回哪個子類型。我不會太在意這個並行,但嘗試這種方式很難匹配語言之間的概念是一個壞主意。

+1

['酒館類型SqliteResult =結果'](https://github.com/linuxfood/rustsqlite/blob/f07a1c3e0e0ce4bbd1ae237f9599edb0394f49e0/types.rs#L121),這意味着['SqliteResult '那'open' returns](https://github.com/linuxfood/rustsqlite/blob/f07a1c3e0e0ce4bbd1ae237f9599edb0394f49e0/lib.rs#L72)爲'Result '(然後查看['Result'](http ://static.rust-lang.org/doc/master/std/result/enum.Result.html)的定義以及可以做什麼)。 –

4

This function open returns SqliteResult<Database>;給定定義pub type SqliteResult<T> = Result<T, ResultCode>,即std::result::Result <Database, ResultCode>

Result是一個enum,你基本上不能訪問枚舉的變體沒有匹配:也就是說,在字面上,唯一的辦法。當然,你可能有抽象的匹配方法,但它們必須用匹配來實現。

您可以從結果文件,它確實有方便的方法,如is_err,這大約是看到這個(這不是正是這一點,但足夠接近):

fn is_err(&self) -> bool { 
    match *self { 
     Ok(_) => false, 
     Err(_) => true, 
    } 
} 

unwrap(再次只是近似):

fn unwrap(self) -> T { 
    match self { 
     Ok(t) => t, 
     Err(e) => fail!(), 
    } 
} 

正如你所看到的,這些是通過匹配實現的。在這種情況下,使用匹配是編寫此代碼的最佳方式。

3

我只是在學習Rust自己,但這是處理這個問題的另一種方法。

if let Ok(database) = sqlite::open("test.db") { 
    // Handle success case 
} else { 
    // Handle error case 
} 

查看documentation about if let

+0

對於這個記錄,2013年當這個問題被問到時,「如果讓」不可用。 ['如果let'是在一年後添加的。](https://github.com/rust-lang/rust/pull/17634)儘管如此,這並不會讓你的回答產生任何錯誤。 :) –

相關問題