pattern matching也是scala和java之间的重大差异之一,简单的pattern matching类似java中的switch以及if-else判断,比如,

val s = "hello world"
s match {
 case "hello world" => println("match")
 case _ =>
}

val a = 123
a match {
 case 123 => println(a)
 case 456 => println(a)
 case _ =>
}

即便是上述用法也比java方便,java的字符串在1.6之前还是不能用在switch语句中的。在上述代码中match与switch的差别在于match语句如果找不到匹配项就会抛异常,所以在匹配的最后加入了case _来匹配所有的漏网之鱼。match匹配上一项后就不会继续匹配下去,于是也省掉了break语句。自然有人希望某些情况下能够像switch一样连续匹配多项后再退出,scala也可以完全满足这点,例如,

 // java
 public static boolean verify(int num) {
   switch (num) {
     case 123:
     case 456:
     case 789: return true;
     default: return false;
   }
 }
// scala
def verify(num: Int): Boolean => {
 num match {
   case 123 | 456 | 789 => true
   case _ => false
 }
}

scala在case语句中可以组合不同条件,无疑scala的表达方式更容易理解。除了用于比较值之外,pattern matching也可以用来进行类型匹配,例如,

def verify(x: Any): Boolean = {
 x match {
   case s: String => true
   case a: Int => true
   case m: Map[_, _] => true
   case s: Set[_] => true
   case _ => false
 }
}

不得不说表达能力以及可读性都超出相应java语句。pattern matching还可以做一些更高级的事情,比如匹配case class,

sealed class Base

case class Foo(name: String) extends Base
case class Bar(name: String, value: Int) extends Base
case class Foobar(foo: Foo, bar: Bar) extends Base

def verify(x: Base) = {
 x match {
   case Foo("foo") => "foo"
   case Bar("bar", _) => "bar"
   case Foobar(Foo("foo1"), Bar("bar1", 1)) => "foobar"
   case _ => "not match"
 }
}

println(verify(Foo("foo")))
println(verify(Bar("bar", 100)))
println(verify(Foobar(Foo("foo1"), Bar("bar1", 1))))
println(verify(Foo("hello"))) // not match

简而言之case class是可以用在case语句中的特殊class类别。Scala会默默为case实现equals、hashCode、toString方法,同时也会生成一个工厂方法来创建对象以避免显示调用new操作。有了case class,我们就可以用它来匹配类实例属性了,比如上述代码中就比较了name字段为foo的Foo对象实例。这种写法比Java中的if-else复杂判断简化很多,用起来会爽很多。此外,case语句还可以包含一些条件判断,

val v = 100
v match {
 case m: Int if m > 50 => true
 case _ => false
}

在匹配的同时,scala也提供了从case语句中获取变量的能力,比如,

val x = Foobar(Foo("foo"), Bar("bar", 0))
x match {
 case Foobar(f @ Foo(_), Bar(n @ _, 0)) => println(f.name + n) // foobar
 case _ =>
}

x match {
 case Foobar(f @ (Foo("foo1") | Foo("foo")), Bar(n @ ("bar1" | "bar"), 0)) => println(f.name + n) // foobar
 case _ =>
}

变量名与case条件之间通过@符号分隔,@后面可以是单个条件或是多个条件的组合。

scala中的pattern matching能力感觉都接近jess中的规则匹配了,用pattern matching来进行条件判断比用一长串if-else清爽多了,这点在用jess的时候就曾有体会。