Skip to content

Latest commit

 

History

History
121 lines (92 loc) · 3.38 KB

专题3——提取器.md

File metadata and controls

121 lines (92 loc) · 3.38 KB

专题 3 —— 提取器

一、提取器概念

  1. 提取器对象是一个包含有 unapply 方法的单例对象。
  2. unapply 方法接受一个实例对象然后返回最初创建它所用的参数。
  3. 提取器常用在模式匹配[^,]+和偏函数中。

二、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)