一、守卫 var ch = ‘+’ ch match { case '+' => sign = 1 case '-' => sign = -1 case _ if Character.isDigit(ch) => digit= Character.digit(ch, 10) case _ => sign = 0 }
二、模式中的变量如果在case关键字后跟着一个变量名,那么匹配的表达式会被赋值给那个变量。case _是这个特性的一个特殊情况,变量名是_。 'Hello, world' foreach { c =>println ( c match { case ' ' => 'space' case ch => 'Char: ' + c } )}
三、类型模式相比使用isInstanceOf来判断类型,使用模式匹配更好 obj match { case x: Int => x case s: String => Integer.parseInt(s) case _: BigInt => Int.MaxValue case _ => 0 }捕获异常: val file = new File(fileName) try { Source.fromFile(file).getLines() }catch{ case e1: FileNotFoundException=> println('FileNotFoundException') case e2: RuntimeException =>println('RuntimeException') case e3: Exception =>println('Exception') }因为匹配是发生在运行期的,而且JVM中泛型的类型信息会被擦掉,因此不能使用类型来匹配特定的Map类型
四、匹配数组、列表和元组1)数组 valarr = Array(0,3,4,5,6,7) arr match { case Array(0) => '0' case Array(x, y) => x + ' '+ y case Array(0, x @_*) => println(x) case _ => 'something else' }2) 列表 val arr = List(0,4,5,6,7,) arrmatch { case List(0) => '0' case List(x, y) => x + ' ' + y case List(0, x @_*) => println(x) case _ => 'something else' } 或者 arr match { case 0 :: Nil => '0' case x :: y :: Nil => x + '' + y case 0 :: tail => '0...' case _ => 'somethingelse' }
五、提取器模式匹配来对数组、列表和元组进行了匹配,在这个过程的背后的是提取器(extractor)机制。使用unapply来提取固定数量的对象,使用unapplySeq来提取一个序列。在前面的代码 case Array(0, x) => ...中, Array(0, x)部分实际上是使用了伴生对象中的提取器,实际调用形式是: Array.unapplySeq(arr)。根据Doc,提取器方法接受一个Array参数,返回一个Option。1)正则表达式是另一个适用提取器的场景。正则有分组时,可以用提取器来匹配分组 val pattern = '([0-9]+)([a-z]+)'.r '99 bottles' match {casepattern(num, item) => (num, item)}2)自定义提取器;下面的例子显示电子邮件地址的提取器对象:object Test { def main(args: Array[String]) { println ('Apply method : ' +apply('Zara', 'gmail.com')); println ('Unapply method : ' +unapply('Zara@gmail.com')); println ('Unapply method : ' +unapply('Zara Ali')); } // The injection method (optional) def apply(user: String, domain: String) = { user +'@'+ domain } // The extraction method (mandatory) def unapply(str: String): Option[(String,String)] = { val parts = str split '@' if (parts.length == 2){ Some(parts(0), parts(1)) }else{ None } }}
六、变量声明中的模式 val (x, y) = (1, 2) val (q, r) = BigInt(10) /% 3 // 返回商和余数的对偶 val Array(first, second, _*) =arr // 将第一和第二个分别给first和second
七、for表达式中的模式 importscala.collection.JavaConversions.propertiesAsScalaMap for ((k, v) <-System.getProperties()) // 这里使用了模式 println(k + ' -> ' + v) for ((k, '') <-System.getProperties()) // 失败的匹配会被忽略,所以只打印出值为空的键 println(k)
八、样例类 abstract class Amount // 继承了普通类的两个样例类 case class Dollar(value: Double) extends Amount case class Currency(value: Double, unit:String) extends Amount // 样例对象 case object Nothing extends Amount amt match { case Dollar(v) => '$' + v case Currency(_, u) => 'Oh noes, Igot ' + u case Nothing => '' //样例对象没有() }在声明样例类时,下面的过程自动发生了:构造器的每个参数都成为val,除非显式被声明为var,但是并不推荐这么做;在伴生对象中提供了apply方法,所以可以不使用new关键字就可构建对象;提供unapply方法使模式匹配可以工作;生成toString、equals、hashCode和copy方法,除非显示给出这些方法的定义。除了上述之外,样例类和其他类型完全一样,方法字段等。
九、匹配嵌套结构 abstarct class Item case class Article(description: String,price: Double) extends Item case class Bundle(description: String, price:Double, items: Item*) extends Item Bundle('Father's day special',20.0, Article('Scala for the Impatient',39.95), Bundle('Anchor DistillerySampler', 10.0, Article('Old Potrero Straight RyeWhisky', 79.95), Article('Junipero Gin', 32.95) ) ) 模式可以匹配到特定的嵌套: case Bundle(_, _, Article(descr, _), _*) =>descr
十、密封类当使用样例类来做模式匹配时,如果要让编译器确保已经列出所有可能的选择,可以将样例类的通用超类声明为sealed。密封类的所有子类都必须在与该密封类相同的文件中定义。如果某个类是密封的,那么在编译期所有的子类是可知的,因而可以检查模式语句的完整性。让所有同一组的样例类都扩展某个密封的类或特质是个好的做法。 sealed abstract class TrafficLightColor case object Red extends TrafficLightColor case object Yellow extends TrafficLightColor case object Green extends TrafficLightColor color match { case Red => 'stop' case Yellow => 'hurry up' case Green => 'go' }
十一、Option类型Option类型用来表示可能存在也可能不存在的值。样例子类Some包装了某个值,而样例对象None表示没有值。Option支持泛型。 val map = Map(3 -> “a”, 4 -> “b”) map.get(3) match { case Some(x) => x case Nome }
十二、偏函数被包在花括号内的一组case语句是一个偏函数。偏函数是一个并非对所有输入值都有定义的函数,是PartialFunction[A, B]类的一个实例,其中A是参数类型,B是返回类型。该类有两个方法:apply方法从匹配的模式计算函数值;isDefinedAt方法在输入至少匹配其中一个模式时返回true。 val f:PartialFunction[Char, Int] = { case '+' => 1; case '-' => -1 } f('-') //返回-1 f.isDefinedAt('0') //false f('0') //抛出MatchError