前面說過,在寫模式匹配時(shí),你必須保證你所寫的可選項(xiàng)覆蓋了全部的可能性,因此常常你必須加上一個(gè)缺省通配符選項(xiàng)。但這種情況只適應(yīng)于缺省通配符有意義的情況。如果對于一些沒有缺省項(xiàng)的情況,你怎么才能保證你寫的可選項(xiàng)是完全的呢?
實(shí)際上,你可以借助于 Scala 編譯器來幫忙,要做到這一點(diǎn),編譯器需要預(yù)先知道所有可能的匹配項(xiàng),這種通常情況下是不可能的。比如你總可以派生出新的子類,然后再可選項(xiàng)中添加這個(gè)新創(chuàng)建的子類的模式。
一種可能的實(shí)現(xiàn)是為基類添加上 Sealed 關(guān)鍵字,一個(gè) sealed 的類只能在定義它的同一個(gè)文件中定義它的子類。這樣你就只需要關(guān)心已經(jīng)定義的子類,如果你使用這些子類做為模式定義,如果可選項(xiàng)不去全的話,編譯器會(huì)自動(dòng)警告。
我們還是使用之前定義的表達(dá)式的例子:
sealed abstract class Expr
case class Var(name:String) extends Expr
case class Number(num:Double) extends Expr
case class UnOp(operator:String, arg:Expr) extends Expr
case class BinOp(operator:String,left:Expr,right:Expr) extends Expr
下面我們定義一個(gè)不完全的模式匹配:
def describe(e:Expr) :String =e match{
case Number(_) => "a number"
case Var(_) => "a variable"
}
<console>:12: warning: match may not be exhaustive.
It would fail on the following inputs: BinOp(_, _, _), UnOp(_, _)
def describe(e:Expr) :String =e match{
^
describe: (e: Expr)String
編譯器給出警告,表示你的定義可能會(huì)拋出 MatchError 異常,因?yàn)?BinOp 和 UnOp 沒有定義在模式定義中。
當(dāng)有的時(shí)候,你可能只需要匹配部分模式,一是添加一個(gè)缺省匹配,比如通配符模式,例如:
def describe(e:Expr) :String =e match{
case Number(_) => "a number"
case Var(_) => "a variable"
case _ => throw new RuntimeException
}
為簡潔起見,Scala 支持使用標(biāo)注 (annotation) 的方法暫時(shí)取消編譯器檢查模式定義是否完備,為變量添加 @unchecked 標(biāo)注后,編譯器不再給出警告:
def describe(e:Expr) :String =(e: @unchecked) match{
case Number(_) => "a number"
case Var(_) => "a variable"
}
@unchecked 在模式匹配中具有特殊意義,如果模式匹配的變量使用該標(biāo)準(zhǔn),Scala 編譯器不對該模式進(jìn)行完備性檢查。