上一篇提到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进行优化。