程式扎記: [Scala 小學堂] Scala Gossic : 繼續深入 - 模式比對 (密封類別)

標籤

2016年7月12日 星期二

[Scala 小學堂] Scala Gossic : 繼續深入 - 模式比對 (密封類別)

Source From Here 
密封類別(Sealed class)
如果你寫了以下的 案例類別
  1. case class Point(x: Int, y: Int)  
  2. case class Circle(p: Point, r: Int)  
  3. case class Cylinder(c: Circle, h: Int)  
若你想寫個函式進行模式比對,對於傳入的物件看看是不是點、圓或柱的一種:
  1. def what(a: Any) = a match {  
  2.     case Point(_, _)    => "點"  
  3.     case Circle(_, _)   => "圓"  
  4.     case Cylinder(_, _) => "柱"  
  5. }  
也許你的案例類別較多,或者是你一時寫錯了,少寫了其中幾個案例 ( Circle), 程式可以如常編譯,但若你傳入了個 Circle,則會發生 scala.MatchError。對於在進行模式比對時,一定要出現的案例類型,可以將之 密封Sealed),例如:
  1. sealed abstract class Drawing  
  2. case class Point(x: Int, y: Int) extends Drawing  
  3. case class Circle(p: Point, r: Int) extends Drawing  
  4. case class Cylinder(c: Circle, h: Int) extends Drawing  
你使用 sealed 關鍵字修飾類別,則繼承該類別的子類別,必須與該父類別位於同一個原始碼中,你也可以使用 sealed 修飾特徵(Trait),例如:
  1. sealed trait Drawing  
  2. case class Point(x: Int, y: Int) extends Drawing  
  3. case class Circle(p: Point, r: Int) extends Drawing  
  4. case class Cylinder(c: Circle, h: Int) extends Drawing  
如果你如之前,少寫了其中一個案例:
  1. def what(d: Drawing) = d match {  
  2.     case Point(_, _)    => "點"  
  3.     case Cylinder(_, _) => "柱"  
  4. }  
則編譯器會提出警示訊息:


編譯器在告訴你,有些模式的類型你沒有列在 match 運算式的案例串(Case sequence)之中。你必須每個都列出來才可以. 有時候,你使用別人密封過的案例類別,但也許你真的只想比對其中幾個案例類型,如果不想要編譯器惱人的警示訊息,則可以在最後使用萬用字元模式,例如:
  1. def what(d: Drawing) = d match {  
  2.     case Point(_, _)    => "點"  
  3.     case Cylinder(_, _) => "柱"  
  4.     case _              => "" // 作你想作的事,或者丟出例外  
  5. }  
如果真的不想要使用萬用字元作額外處理,那麼也可以使用 @unchecked 標註(Annotation)來告訴編譯器住嘴:
  1. sealed trait Drawing  
  2. case class Point(x: Int, y: Int) extends Drawing  
  3. case class Circle(p: Point, r: Int) extends Drawing  
  4. case class Cylinder(c: Circle, h: Int) extends Drawing  
  5.   
  6. def what(d: Drawing) = (d: @unchecked) match {  
  7.     case Point(_, _)    => "點"  
  8.     case Cylinder(_, _) => "柱"  
  9. }  
  10.   
  11. val p = Point(12)  
  12. val c = Circle(p, 5)  
  13. val cy = Cylinder(c, 10)  
  14. println(what(p))        // 點  
  15. // println(what(c))     // Will throws scala.MatchError  
  16. println(what(cy))       // 柱  


沒有留言:

張貼留言

網誌存檔