Scala之旅——提取器对象

一个提取器对象会有一个unapply方法。apply方法类似于接受参数并创建对象的构造器,反过来unapply则是接受一个对象并试图返回原来的参数。这一点在模式匹配和偏函数中经常使用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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方法也可以用来分配一个值。

1
2
3
val customer2ID = CustomerID("Nico")
val CustomerID(name) = customer2ID
println(name) // prints Nico

这个其实和val name = CustomerID.unapply(customer2ID).get是等价的。

1
val CustomerID(name2) = "--asdfasdfasdf"

如果没有匹配上,则抛出一个scala.MatchError

1
val CustomerID(name3) = "-asdfasdfasdf"

关于unapply的返回类型有以下几种选择:

  • 如果仅仅是一个判断,则返回一个Boolean。例如case even()
  • 如果要返回T类型的单个子值,则返回一个Option[T]
  • 如果要返回多个子值如T1,...,Tn,则可以把它们组合起来放在一个可选的元组Option[(T1,...,Tn)]当中。

有时候子值的数量不固定,我们则可以返回一个序列。因此这时候,你就可以通过定义unapplySeq的方式来返回一个Option[Seq[T]],这种用法常见于case List(x1, ..., xn)模式中。

小鹏 wechat
公众号:数据Man
0%