是怎樣的頭部和尾部在下面的語句來確定:Scala Cons模式匹配如何確定List的頭部和尾部?
val head::tail = List(1,2,3,4);
//head: 1 tail: List(2,3,4)
不應該有一些代碼段,用於提取第一元素作爲頭,並返回尾巴作爲一個新的列表。我一直在梳理Scala標準庫代碼,我找不到/瞭解如何/在哪裏完成。
是怎樣的頭部和尾部在下面的語句來確定:Scala Cons模式匹配如何確定List的頭部和尾部?
val head::tail = List(1,2,3,4);
//head: 1 tail: List(2,3,4)
不應該有一些代碼段,用於提取第一元素作爲頭,並返回尾巴作爲一個新的列表。我一直在梳理Scala標準庫代碼,我找不到/瞭解如何/在哪裏完成。
此處涉及的Scala構造是Extractor。符號::
不過是Scala中的一個案例類,其伴侶對象上存在一個unapply
方法,以使提取魔法發生。 Here是關於提取器的深入教程。但是總結如下:
無論何時你想「解壓縮」一個類的內容,無論是用於變量綁定還是作爲模式匹配的一部分,編譯器都會在左側的任何符號上尋找方法unapply
的表達。這可能是一個對象,一個case類伴侶對象(如::
,在你的問題中),或者一個帶有unapply
的實例。 unapply
的參數是要解包的傳入類型,返回類型是已聲明爲預期結構和類型的Option
。在模式匹配中,None
表示未找到匹配項。在變量綁定中,如果None
是結果,則引發MatchError
。
關於unapply
的一個好方法是它與apply
相反。其中unapply
是函數調用語法的接收者,unapply
是提取者調用的接收者。
爲了進一步說明這一點,讓我們定義一個簡單的例子類:
case class Cat(name: String, age: Int)
因爲它是一個案例類,我們得到自動產生的同伴對象,這大致是這樣的apply
和unapply
方法:
object Cat {
// compiler generated...
def apply(name: String, age: Int) = new Cat(name, age)
def unapply(aCat: Cat): Option[(String, Int)] = Some((aCat.name, aCat.age))
}
當您通過伴隨對象創建Cat
時,將調用apply
。當您打開一個Cat
的組成部分,unapply
被稱爲:
val mycat = Cat("freddy", 3) // `apply` called here
...
val Cat(name, age) = mycat // `unapply` called here
...
val animal: AnyRef = mycat
val info = animal match {
case Cat(name, age) => "My pet " + name // `unapply` called here
case _ => "Not my pet"
}
// info: String = My pet freddy
因爲unapply
返回一個Option
,我們有大量的電力來編寫處理更有趣的情況下,例如提取,檢測是否進入的類型在提取值之前符合一些標準。例如,假設我們想要得到「舊」貓的名字。有人可能會做到這一點:
object OldCatName {
def unapply(aCat: Cat) = if (aCat.age >= 10) Some(aCat.name) else None
}
用法是相同的生成unapply
:
val yourcat = Cat("betty", 12)
...
val OldCatName(name1) = yourcat
// name1: String = "betty"
val OldCatName(name2) = mycat
// scala.MatchError: Cat(freddy,3) (of class Cat)
MatchError
s爲不是一件好事,讓,讓我們使用模式匹配:
val conditions = Seq(mycat, yourcat) map {
case OldCatName(oldie) => s"$oldie is old"
case Cat(name, age) => s"At age $age $name is not old"
}
// conditions: Seq[String] = List(At age 3 freddy is not old, betty is old)
與unapply
方法::
有關的一個額外的魔法是一些語法糖允許val ::(head, tail) = ...
改寫爲val head :: tail = ...
。
http://blog.lunatech.com/2011/11/25/scala-list-extractor-demystified很好的解釋它是如何工作的 – 2014-09-20 02:45:07
@ eugene-zhulenev,謝謝你的鏈接。這是現貨。 Cons案例類自動提供了構造List實例並將其解構爲頭部和尾部的方法。 – poissondist 2014-09-20 03:03:13
@poissondist來自eugene zhulenev的鏈接已損壞。你如何看待我的答案? – metasim 2016-06-14 21:45:45