1. 程式人生 > >話說模式匹配(8) 一個抽取器的例子

話說模式匹配(8) 一個抽取器的例子

一個抽取器的例子

目前List的序列模式(sequence pattern)可以支援對前邊若干元素的匹配,比如:List(1,2,3,_*),如果想要實現 List(_*, lastEle) 這樣的形式,就需要通過自定義一個抽取器來實現了

// 自定義Extractor
object Append {
    // 接受List結構
    def unapply[A] (l: List[A]) = {
        // 返回Tuple2:前邊的若干元素和最後一個元素
        Some( (l.init, l.last) )
    }
}

抽取器裡的unapply方法,入參對應你想要進行匹配的物件,出參則是解構後的元素。
比如 list match { case Append(x,y) => }

裡面的list對應unapply的入參,x,y對應unapply方法的出參。

為什麼unapply方法的返回結果大多都使用Some包裝一下,這其實是unapply方法返回值的一些約束

  1. 返回Boolean,那麼匹配時 case A() 裡面的true不用寫(也不能寫)
  2. 若原本想要返回型別為T,則使用Option[T],這樣是為了匹配時能夠判斷是否成功,Some[T] 成功,None不成功
  3. 若原本想要返回一組T1,…Tn,則使用Option[(T1,…Tn)]

現在看看上面自定義抽取器的使用例子:

scala> (1 to 9).toList match{ case _ Append 9 => println("OK") }
OK

scala> (1 to 9).toList match{ case x Append 8 Append 9 => println("OK") }
OK

上面使用了中綴寫法,也可以寫成普通的構造方式,只是看起來沒有上面的舒服

scala> (1 to 9).toList match{ case Append(Append(_,8),9) => println("OK") }
OK

另外,如果覺得Append這個名字太囉嗦,抽取器object單例名稱也可以用符號表達,比如用”:>“來表示

object :> {
    // unapply ...
}

這樣對匹配時的表達顯得更簡短一些

scala> (1 to 9).toList match{ case x :> 8 :> 9 => println("OK") }
OK

另外,以”:“結尾的符號支援從右到左的操作方式,List的子類就採用了“::”這樣的名稱,以方便模式匹配(當然也是因為早期的一些函式式語言裡,如ML裡已經定義了::的形式,scala只是延續而已)。