Scala 专题教程-Extractors(4): 可变参数的Extractors

jerry Scala 2015年11月25日 收藏

前面的几个例子中Extractor返回的结果的数目都是固定的,比如EMail返回两个:用户名和域名。有些时候,这显得有些不够灵活。比如你打算匹配一个域名,而返回的部分为域名的各个部分,你可能会写如下的模式:

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

这个例子的模式定义有很大的局限性,只能匹配acm.org, java.sun.com 和*.net域名。问题是我们如何实现可以匹配任意类型的域名,并分解出域名的各个部分。
针对这种变长类型的匹配,Scala 定义了一个unapplySeq方法来支持这种用法,例如:

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

对象Domain定义unapplySeq方法,首先以“.?分割字符串,Split使用正规表达式,因此.需要使用\\转义。unapplySeq 结果返回一个封装在Some的Seq数据。
然后你可以使用Domain Extractor 来获取Email地址更详细的信息。比如查找用户名为?tom?,域名为某些含?com”的地址。

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

测试如下:

  1. scala> isTomDotCom("tom@sun.com")
  2. res0: Boolean = true
  3.  
  4. scala> isTomDotCom("peter@sun.com")
  5. res1: Boolean = false
  6.  
  7. scala> isTomDotCom("tom@acm.org")
  8. res2: Boolean = false
  9.  

使用unapplySeq 也支持返回一部分固定长度的变量加上后面变长的变量,这个返回值可以表示成一多元组,可变的部分放在最后。比如:

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

的unapplySeq返回一个二元组,第一个元素为用户名,第二个元素为一个Seq包含域名的所有部分。

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