程式扎記: [Scala 小學堂] Scala Gossic : 繼續深入 - 模式比對 (Option 型態)

標籤

2016年7月11日 星期一

[Scala 小學堂] Scala Gossic : 繼續深入 - 模式比對 (Option 型態)

Source From Here
Option 型態
當你呼叫了某個函式或執行了某個物件方法,函式或方法可能有傳回物件,也有可能沒有結果,如果沒有結果時,Scala 不建議傳回 null。來看看一個例子,若你設計了一個 doSomeUpper() 函式:
  1. def doSomeUpper(x: String) = {  
  2.     if(x == "some") x.toUpperCase else null  
  3. }  
有人可能會使用你的這個函式,如果他有查看過你提供的 API 文件,或者知道函式有可能傳回 null,那他應該這麼使用這個函式:
  1. val result = doSomeUpper("other")  
  2. if(result != null) println(result(0)) else println("...XD")  
如果他忘了要對傳回結果作 null 檢查,那麼就會有可能發生 NullPointerException. 讓函式或方法傳回 null,對於使用該函式或方法的客戶端,沒有一個方式提醒或強制他們處理可能傳回的 null,因而在程式中有可能發生 NullPointerException

對於一些有可能傳回也可能不傳回物件的函式或方法,Scala 建議你傳回 scala.OptionOption 有兩個子類別:scala.Some 與 scala.None。有傳回物件時,可以使用 Some 包裹傳回物件,沒有傳回物件時,可直接傳回 None。你可以這麼改寫先前的函式:
  1. def doSomeUpper(x: String) = {  // 傳回型態為Option[String]  
  2.     if(x == "some") Some(x.toUpperCase) else None  
  3. }  
這個函式一定會傳回物件,型態為 Option[String]因為 Scala 類型推斷的特性,所以沒有在定義函式時標示出傳回型態),要不就是 Some,要不就是 None。那麼要如何使用呢?
  1. val result = doSomeUpper("other")  
  2. println(result.getOrElse("...XD"))  
Option 有個 getOrElse() 方法,如果傳回結果包裹在 Some 中,則 getOrElse() 會取出包裹在當中的物件,如果傳回 None,則取得你指定給 getOrElse() 的物件,藉由傳回 Option 物件,可以避免使用方法或函式的客戶端,因為沒有處理 null 的情況,而有發生NullPointerException 的可能性。

Scala 中群集物件的一些方法傳回值就是 Option 型態,例如 Map 的 get() 方法:
  1. val rooms = Map(101 -> "Justin"102 -> "caterpillar")  
  2. // get() 傳回型態是 Option[String]  
  3. println(rooms.get(101).getOrElse("empty")) // Justin  
  4. println(rooms.get(102).getOrElse("empty")) // caterpillar  
  5. println(rooms.get(103).getOrElse("empty")) // empty  
Some 與 None 在定義時,都使用了 case 關鍵字修飾,所以上例可以改用模式比對的方式來處理傳回結果:
  1. def name(o: Option[String]) = o match {  
  2.     case Some(r) => r  
  3.     case None    => "empty"  
  4. }  
  5.   
  6. val rooms = Map(101 -> "Justin"102 -> "caterpillar")  
  7. println(name(rooms.get(101)))       // Justin  
  8. println(name(rooms.get(102)))       // caterpillar  
  9. println(name(rooms.get(103)))       // empty  
如果你有一個 List 中包括了數個函式的執行結果,而每個執行結果是以 Option 來傳回,也就是有結果時,用 Some 包裹,沒有結果時是 None,則在想要取得結果時,就可以如下方便地結合 for 迴圈:
scala> val list = List(Some("John"), None, Some("Peter"))
list: List[Option[String]] = List(Some(John), None, Some(Peter))

scala> for(Some(result) <- font="" list="" println="" result="">
John
Peter


沒有留言:

張貼留言

網誌存檔

關於我自己

我的相片
Where there is a will, there is a way!