上一篇提到scala中的pattern matching的不少特性,但scala对此的支持还不止于此,它另外还支持一种名为extractor的匹配方式,

object Email {
 def unapply(input: String): Option[(String, String)] = {
   val splits = input.split("@")
   if (splits.length == 2) {
     Some(splits(0), splits(1))
   } else {
     None
   }
}

val Email(user, domain) = "foo@bar.com"
println(user)   // foo
println(domain) // bar.com

"foo@bar.com" match {
 case Email(user, domain) => println(user)  // foo
 case _ =>
}

上述代码中的email就是一个extractor,extractor需要定义一个unapply函数,函数返回类型为Option或是Boolean,接受的参数类型不受限制。从上面的例子来看,extractor不仅可以用在变量定义中也可以用于match语句,用于match时类似如下这种case class使用,

case class Email(user: String, domain: String) {
 def this(input: String) {
   this(input.split("@")(0), input.split("@")(1))
 }
}

val email = new Email("foo@bar.com")
email match {
 case Email(user @ _, domain @ _) => println(user)
}

可以看到case class也可以做到同样的事情,那extractor与case class的主要差异在哪呢?从上面代码也可以看出使用case class匹配时需要对应的构造函数才行,case语句中的匹配项与构造函数是一一对应的,而extractor就没有这点问题programming in scala提到的术语是“representation independence”。如果你完全掌控着所有代码,那用case class也是有好处的,比如编译器容易对case class进行优化。