提取器对象
一个提取器对象会有一个 unapply 方法。 apply 方法类似于接受参数并创建对象的构造器,反过来 unapply 则是接受一个对象并试图返回原来的参数。这一点在模式匹配和偏函数中经常使用。
import scala.util.Random
object CustomerID {
def apply(name: String) = s"$name--${Random.nextLong}"
def unapply(customerID: String): Option[String] = {
val stringArray: Array[String] = customerID.split("--")
if (stringArray.tail.nonEmpty) Some(stringArray.head) else None
}
}
val customer1ID = CustomerID("Sukyoung") // Sukyoung--23098234908
customer1ID match {
case CustomerID(name) => println(name) // prints Sukyoung
case _ => println("Could not extract a CustomerID")
}
apply 方法由一个 name 创建了一个 CustomerID 字符串。 unapply 则反过来获得了 name 。当我们调用 CustomerID("Sukyoung") 时,其实是 CustomerID.apply("Sukyoung") 的一种简写形式。而当我们调用 case CustomerID(name) => println(name) 时,则实际调用的是 unapply 方法。
另外 unapply 方法也可以用来分配一个值。
val customer2ID = CustomerID("Nico")
val CustomerID(name) = customer2ID
println(name) // prints Nico
这个其实和 val name = CustomerID.unapply(customer2ID).get 是等价的。
val CustomerID(name2) = "--asdfasdfasdf"
如果没有匹配上,则抛出一个 scala.MatchError:
val CustomerID(name3) = "-asdfasdfasdf"
关于 unapply 的返回类型有以下几种选择:
- 如果仅仅是一个判断,则返回一个
Boolean。例如case even()。 - 如果要返回
T类型的单个子值,则返回一个Option[T]。 - 如果要返回多个子值如
T1,...,Tn,则可以把它们组合起来放在一个可选的元组Option[(T1,...,Tn)]当中。
有时候子值的数量不固定,我们则可以返回一个序列。因此这时候,你就可以通过定义 unapplySeq 的方式来返回一个 Option[Seq[T]] ,这种用法常见于 case List(x1, ..., xn) 模式中。