1.通配模式
通配符 “_” 可以用来匹配任意对象。通常在模式匹配中作为最后一个匹配项,匹配其它所有的输入对象。比如:
abstract class Expr case class Var(name:String) extends Expr case class Number(num:Double) extends Expr case class BinOp(operator:String,left:Expr,right:Expr) extends Expr def simplifyBinOp(expr :Expr) = expr match { case BinOp(op,left,right) => println( expr + " is a binary operation") case _ => }
通配模式也可以用来忽略一些你不打算处理的对象,比如在本例中,只关心输入是否为一个二元操作,其它的直接忽略。如果你不关心具体的操作符,如左右操作符,可以直接使用通配符忽略这些部分,如:
def simplifyBinOp(expr :Expr) = expr match { case BinOp(_,_,_) => println( expr + " is a binary operation") case _ => }
2.常量模式
常量模式可以匹配和常量值本身相同的输入。任意的字面量都可以作为常量模式。此外,所有的单例(singleton)也可以作为常量模式。比如 Nil 可以匹配空列表。
def describe(x:Any) =x match { case 5 => "five" case true => "truth" case "hello" => "hi!" case Nil => "the empty list" case _ => "something else" }
本例定义了多个常量模式,我们来看看一些测试结果:
scala> describe (5) res0: String = five scala> describe(true) res1: String = truth scala> describe ("hello") res2: String = hi! scala> describe(Nil) res3: String = the empty list scala> describe(List(1,3,4)) res4: String = something else3.变量模式
一个变量模式可以匹配任意对象,在这一点上和通配符 “_” 一样。但和通配符不同的是, Scala 将这个变量绑定到输入的对象上,然后你在后面定义的表示中可以引用这个变量。比如下面代码匹配 0 ,对于其它的对象使用了变量模式,这其后的表示中可以引用这个变量:
def isZero(x:Any) = x match{ case 0 => "zero" case somethingElse => "not zero:" + somethingElse }
对于somethingElse变量,出了0其他的值都会匹配到它。
scala> isZero(0) res5: String = zero scala> isZero(1) res6: String = not zero:1
4.构造器模式
构造器模式功能非常强大,比如一个构造器模式可以定义为 BinOp(“+”,e,Number(0)) 。 它由一个名称 BinOp (某个case class的名称)和一系列由括号分开的模式构成( “+” , e 和 Number(0) )。这个模式首先检查输入对象是否是 BinOp 类型的对象,然后检查构造器参数是否匹配输入的对象。
这些额外的模式表示 Scala 支持深度匹配,这些模式不仅仅检查最高层次的匹配,并且检查其内部内容的匹配,同时这些额外的模式自身还可以是构造器模式,因此你可以构造嵌套任意层次的构造器模式。比如:
def simplifyBinOp(expr :Expr) = expr match { case BinOp("+",e,Number(0)) => println(" a deep match") case _ => }它的第三个参数Number(0)自身也是一个构造器模式,其参数又匹配0,因此有3个层次的匹配。
5.序列模式
你也可以匹配如 List 和数组等序列类型的数据。和匹配 case class 语法类似,但你可以指明序列中任意数量的元素。比如下面这个例子,匹配了含有三个元素且其中首元素为 0 的列表:
List(0,2,4) match{ case List(0,_,_) => print ("found it " ) case _ => }如果你需要匹配一个未指明长度的序列,可以使用 “_*” 作为模式的后一元素,这个 “_*” 可以匹配任意数目的元素(包括0个元素)。
6.多元组模式
除序列外,你可以匹配多元组,比如:
def tupleDemo(expr:Any) = expr match{ case (a,b,c) => print("matched " + a +":" +b +":"+c ) case _ => } scala> tupleDemo(2,3,4) matched 2:3:4
7.类型模式
你可以使用类型模式匹配来代替类型检查和类型转换。比如:
def generalSize(x:Any) = x match{ case s:String => s.length case m:Map[_,_] => m.size case _ => -1 }
函数 generalSize 返回某些对象长度或是大小。它的参数类型为Any,因此可以传入任意类型的数据。 模式s:String 是一个类型模式,用于匹配任意类型为String的非空对象。变量s为匹配的字符串。
第二个匹配 m:Map[_,_] 用于匹配任意类型的 Map 对象。这里我们不关心具体的 key 和 value ,因此使用通配符 _ 。如果你需要在后面表达式中使用 key 、 value ,可以使用 key,value 替换掉 _ 。对于Map类型的数据,我们能否匹配指定 key 或 value 类型的数据呢,比如:
def isIntIntMap(x:Any) = x match { case m:Map[Int,Int]=>true case _ => false }
此时编译器会给出警告:
<console>:9: warning: non-variable type argument Int in type pattern Map[Int,Int] is unchecked since it is eliminated by erasure case m:Map[Int,Int]=>true ^ isIntIntMap: (x: Any)Boolean
Scala 和 Java 类似,对于 generic 类采用了“type erasure”,也就是说,在运行时不保存 Map 的 Key 和 value 的类型,因此我们无法匹配指定类型 key 或 value 的 Map 对象。
尝试输入下面的语句:scala> isIntIntMap(Map(1->1)) res14: Boolean = true scala> isIntIntMap(Map("a"->"b")) res15: Boolean = true可以看到,这两个都返回 true,这和预期不同。因此,对于这种情况,编译器会给出警告,pattern Map[Int,Int] 中的类型不起作用。
但有一个特例,数组和一般的 generic 处理不同,它支持匹配元素类型。比如:
def isStringArray(x:Any) = x match{ case a:Array[String]=>"yes" case _ => "no" }在 Shell 中输入下方的语句测试一下:
scala> val as =Array("abc") as: Array[String] = Array(abc) scala> isStringArray(as) res16: String = yes scala> val ai = Array(1,2,3) ai: Array[Int] = Array(1, 2, 3) scala> isStringArray(ai) res17: String = no
8.变量绑定
除了独立的变量模式外,你还可以把一个变量添加到另外的模式中。可以简单地定义一个变量,然后再添加一个 @ 符号,然后再写其它的模式。这就定义了一个变量绑定过的模式。这意味着还是按照标准的模式匹配来匹配输入的对象,如果匹配成功,匹配成功的对象会赋值到定义的变量中。
例如:expr match { case UnOp("abs",e @ UnOp("abs",_)) => e case _ => }这里定义了一个绑定到变量的模式, e @ UnOp(“abs”,_) ,而整个模式是匹配运用了两次 “abs” 操作的对象。如果匹配成功,e 将被赋值为匹配 UnOp(“abs”,_) 的部分。比如:
scala> case class UnOp(operator:String, arg:Expr) extends Expr defined class UnOp scala> val expr = UnOp("abs",UnOp("abs",Number(5))) expr: UnOp = UnOp(abs,UnOp(abs,Number(5.0))) scala> expr match { | case UnOp("abs",e @ UnOp("abs",_)) => e | case _ => | } res0: Any = UnOp(abs,Number(5.0))可以看到,匹配 UnOp(“abs”,UnOp(“abs”,Number(5)))成功后,e 赋值为 UnOp(abs,Number(5.0)) 。