鍍金池/ 教程/ Scala/ 可變參數(shù)的 Extractors
定義 Extractor
正規(guī)表達(dá)式
Extractors 和 Seq 模式
可變參數(shù)的 Extractors
無參數(shù)和帶一個(gè)參數(shù)的模式定義
分解 Email 地址的例子

可變參數(shù)的 Extractors

前面的幾個(gè)例子中 Extractor 返回的結(jié)果的數(shù)目都是固定的,比如 EMail 返回兩個(gè):用戶名和域名。有些時(shí)候,這顯得有些不夠靈活。比如你打算匹配一個(gè)域名,而返回的部分為域名的各個(gè)部分,你可能會(huì)寫如下的模式:

dom match{
    case Domain("org","acm") => print("acm.org")
    case Domain("com","sun","java") => println("java.sun.com")
    case Domain("net",_*) => println (" a .net domain")
}

這個(gè)例子的模式定義有很大的局限性,只能匹配 acm.org,java.sun.com 和*.net 域名。問題是我們?nèi)绾螌?shí)現(xiàn)可以匹配任意類型的域名,并分解出域名的各個(gè)部分。

針對這種變長類型的匹配,Scala 定義了一個(gè) unapplySeq 方法來支持這種用法,例如:

object Domain{
    def apply(parts:String *) :String = parts.reverse.mkString(".")
    def unapplySeq(whole:String): Option[Seq[String]] =
        Some(whole.split("\\.").reverse)
}

對象 Domain 定義 unapplySeq 方法,首先以“.”分割字符串,Split 使用正規(guī)表達(dá)式,因此.需要使用\\轉(zhuǎn)義。unapplySeq 結(jié)果返回一個(gè)封裝在 Some 的 Seq 數(shù)據(jù)。

然后你可以使用 Domain Extractor 來獲取 Email 地址更詳細(xì)的信息。比如查找用戶名為“tom”,域名為某些含“com”的地址。

def isTomDotCom(s:String):Boolean =s match{
    case EMail("tom",Domain("com",_*)) => true
    case _ => false
}

測試如下:

scala> isTomDotCom("tom@sun.com")
res0: Boolean = true
scala> isTomDotCom("peter@sun.com")
res1: Boolean = false
scala> isTomDotCom("tom@acm.org")
res2: Boolean = false

使用 unapplySeq 也支持返回一部分固定長度的變量加上后面變長的變量,這個(gè)返回值可以表示成一多元組,可變的部分放在最后。比如:

object ExpendedEMail{
    def unapplySeq(email: String)
        :Option[(String,Seq[String])] ={
        val parts = email split "@"
        if(parts.length==2)
            Some(parts(0),parts(1).split("\\.").reverse)
        else
            None
    }
}

本例的 unapplySeq 返回一個(gè)二元組,第一個(gè)元素為用戶名,第二個(gè)元素為一個(gè) Seq 包含域名的所有部分。

scala> val s ="james.shen@mail.guidebee.com"
s: String = james.shen@mail.guidebee.com
scala> val ExpendedEMail(name,topdomain,subdoms @ _*) =s
name: String = james.shen
topdomain: String = com
subdoms: Seq[String] = WrappedArray(guidebee, mail)