- 提取器对象是一个包含有
unapply
方法的单例对象。 unapply
方法接受一个实例对象然后返回最初创建它所用的参数。- 提取器常用在模式匹配[^,]+和偏函数中。
unapply
方法的返回值应当符合下面的某一条
- 如果只是用来判断真假,可以返回一个
Boolean
类型的值。例如case even()
。 - 如果只是用来提取单个
T
类型的值,可以返回Option[T]
。 - 如果你想要提取多个值,类型分别为
T1,...,Tn
,可以把它们放在一个可选的元组中Option[(T1,...,Tn)]
。
有时,要提取的值的数量不是固定的,因此我们想根据输入来返回随机数量的值。这种情况下,你可以用 unapplySeq
方法来定义提取器, 此方法返回 Option[Seq[T]]
。常见的例子有,用 case List(x, y, z) =>
来解构一个列表 List, 以及用一个正则表达式 Regex 来分解一个字符串 String,例如 case r(name, remainingFields @ _*) =>
。
示例1:不提取值(只判断真假)
object UpperCase {
def unapply(s: String): Boolean = s.toUpperCase == s
}
val s = "AA"
s match {
case x @ UpperCase() => println(x)
case _ => "other"
}
示例2:提取单个值
object Twice {
def apply(s:String) = s + s
def unapply(s:String):Option[String] ={
val length=s.length/2
val half = s.substring(0,length)
if(half == s.substring(length)) Some(half) else None
}
}
示例3:提取多个值(传的元组)
object Email {
def apply(user:String,domain:String) = user + "@" + domain
def unapply(str:String) :Option[(String,String)] ={
val parts = str split "@"
if(parts.length==2) Some(parts(0),parts(1)) else None
}
}
case EMail(user,domain) =>
示例4:提取多个值(传的Seq)
object Domain{
def apply(parts:String *) :String = parts.reverse.mkString(".")
def unapplySeq(whole:String): Option[Seq[String]] =
Some(whole.split("\\.").reverse)
}
case Domain("com",_*) =>
val date = raw"(\d{4})-(\d{2})-(\d{2})".r
查询字符串
val dates = "Important dates in history: 2004-01-20, 1958-09-05, 2010-10-06, 2011-07-15"
regex findPrefixOf str //查询单个
val firstDate = date.findFirstIn(dates).getOrElse("No date found.") //查询单个
regex findAllIn str //查询所有
val allYears = for (m <- date.findAllMatchIn(dates)) yield m.group(1) //查询所有
val mi = date.findAllIn(dates)
while (mi.hasNext) {
val d = mi.next
if (mi.group(1).toInt < 1960) println(s"$d: An oldie but goodie.")
}
替换字符串
val redacted = date.replaceAllIn(dates, "XXXX-XX-XX")
val yearsOnly = date.replaceAllIn(dates, m => m.group(1))
val months = (0 to 11).map { i => val c = Calendar.getInstance; c.set(2014, i, 1); f"$c%tb" }
提取器
//直接匹配
"2004-01-20" match {
case date(year, _*) => s"$year was a good year for PLs."
}
// 非完全匹配
val embeddedDate = date.unanchored
"Date: 2004-01-20 17:25:18 GMT (10 years, 28 weeks, 5 days, 17 hours and 51 minutes ago)" match {
case embeddedDate("2004", "01", "20") => "A Scala is born."
}
// 解构赋值
val date(year, month, day) = "2004-01-20"
for(date(y,m,d) <- date findAllIn input)
println(y,m,d)