如果你寫了以下的 案例類別:
case class Point(x: Int, y: Int)
case class Circle(p: Point, r: Int)
case class Cylinder(c: Circle, h: Int)
若你想寫個函式進行模式比對,對於傳入的物件看看是不是點、圓或柱的一種:
def what(a: Any) = a match {
case Point(_, _) => "點"
case Circle(_, _) => "圓"
case Cylinder(_, _) => "柱"
}
也許你的案例類別較多,或者是你一時寫錯了,少寫了其中幾個案例:
def what(a: Any) = a match {
case Point(_, _) => "點"
case Cylinder(_, _) => "柱"
}
程式可以如常編譯,但若你傳入了個Circle,則會發生 scala.MatchError。
對於在進行模式比對時,一定要出現的案例類型,可以將之密封(Sealed),例如:
sealed abstract class Drawing
case class Point(x: Int, y: Int) extends Drawing
case class Circle(p: Point, r: Int) extends Drawing
case class Cylinder(c: Circle, h: Int) extends Drawing
你使用sealed關鍵字修飾類別,則繼承該類別的子類別,必須與該父類別位於同一個原始碼中,你也可以使用sealed修飾特徵(Trait),例如:
sealed trait Drawing
case class Point(x: Int, y: Int) extends Drawing
case class Circle(p: Point, r: Int) extends Drawing
case class Cylinder(c: Circle, h: Int) extends Drawing
如果你如之前,少寫了其中一個案例:
def what(d: Drawing) = d match {
case Point(_, _) => "點"
case Cylinder(_, _) => "柱"
}
則編譯器會提出警示訊息:
warning: match is not exhaustive!
missing combination Circle
def what(d: Drawing) = d match {
^
missing combination Circle
def what(d: Drawing) = d match {
^
編譯器在告訴你,有些模式的類型你沒有列在match運算式的案例串(Case sequence)之中。你必須每個都列出來才可以:
def what(d: Drawing) = d match {
case Point(_, _) => "點"
case Circle(_, _) => "圓"
case Cylinder(_, _) => "柱"
}
有時候,你使用別人密封過的案例類別,但也許你真的只想比對其中幾個案例類型,如果不想要編譯器惱人的警示訊息,則可以在最後使用萬用字元模式,例如:
def what(d: Drawing) = d match {
case Point(_, _) => "點"
case Cylinder(_, _) => "柱"
case _ => "" // 作你想作的事,或者丟出例外
}
如果真的不想要使用萬用字元作額外處理,那麼也可以使用 @unchecked 標註(Annotation)來告訴編譯器住嘴:
def what(d: Drawing) = (d: @unchecked) match {
case Point(_, _) => "點"
case Cylinder(_, _) => "柱"
}