[Scala]Scala学习笔记十 模式匹配

原创 2017年08月17日 10:07:57

Scala有一个十分强大的模式匹配机制.可以应用在很多场合:switch语句,类型检查等等.此外Scala还提供了样例类,对模式匹配进行了优化.

1. 更好的switch

如下是Scala中C风格switch语句的等效代码:

var sign = 2
val ch = '+'
ch match {
  case '+' => sign = 1
  case '-' => sign = -1
  case _ => sign = 0
}
println(sign) // 1

与default等效的是捕获所有模式(case _模式).有这样一个捕获所有的模式是有好处的.如果没有模式能匹配并且并没有提供case _,代码会抛出MatchError.

与C语言的switch不同的是,Scala模式匹配不会像C语言那样必须在每个分支的末尾显示使用break语句防止进行下一分支.

与if类似,match也是表达式,而不是语句.前面代码可以简化为:

sign = ch match {
  case '+' => 1
  case '-' => -1
  case _ => 0
}

可以在match表达式中使用任何类型,而不仅仅是数字:

color match{
  case Color.RED => ...
  case Color.BLACK => ...
  ...
}

2. 守卫

假如说我们想扩展上面第一个代码以匹配所有数字.在C风格switch语句中可以通过简单的添加多个case标签来实现:

switch(i){
  case 0:
    ...
    break;
  case 1:
    ...
    break;
  ...
  case 9:
    ...
    break;  
  default:
    ...
}

这如果放在Scala中会更简单,给模式添加守卫(相当于一个判断条件)即可:

ch match{
  case '+' => sign = 1
  case '-' => sign = -1
  case _ if Character.isDigit(ch) => digit = Character.digit(ch, 10)
  case _ => sign = 0
}

守卫可以是任何Boolean条件.

备注

模式总是从上往下进行匹配的.如果守卫的这个模式不能匹配,则捕获所有的模式(`case _`)会被用来尝试进行匹配.

3. 模式中的变量

如果case关键字后面跟着一个变量名,那么匹配的表达式会被赋值给那个变量,进而可以在后面中使用该变量:

val character = '1'
character match {
  case '+' => println("this is +")
  case '-' => println("this is -")
  case ch => println("this is " + ch) // this is 1
}

备注

上面代码中如果给定字符不是'+'或者'-',给定字符则会赋值给变量ch

也可以在守卫中使用变量:

val character = '5'
character match {
  case '+' => println("this is +")
  case '-' => println("this is -")
  case ch if Character.isDigit(ch) => println("this is digit") // this is digit
}

4. 类型模式

可以根据表达式的类型进行匹配:

val str:Any = "Hello World"
str match {
  case s: String => println("this is string " + s) // this is string Hello World
  case x: Int => println("this is integer " + x)
  case ch => println("this is other " + ch)
}

在Scala中,我们更倾向于使用这种的模式匹配,而不是使用isInstanceOf操作符.

备注

注意模式中的变量名.当你在匹配类型的时候,必须给出一个变量名(例如上例中的s,x).否则,将会拿对象本身来进行匹配:
case _: BigInt => Int.MaxValue // 匹配任何类型为BigInt的对象
case BigInt => -1 // 匹配类型为Class的BigInt对象

5. 匹配数组,列表和元组

匹配数组中的内容,可以在模式中使用Array表达式:

def arrayMatch(arr:Array[String]) = arr match {
  case Array("Hello") => println("the array only contain 'Hello'")
  case Array(x,y) => println("the array contain two value " + x + " and " + y)
  case Array(x,_*) => println("the array contain many values " + arr.mkString(","))
  case _ => println("the other array")
}

arrayMatch(Array("Hello")) // the array only contain 'Hello'
arrayMatch(Array("Hello", "World")) // the array contain two value Hello and World
arrayMatch(Array("Hello", "World", "Yoona")) // the array contain many values Hello,World,Yoona

同样也可以使用List表达式(或者使用::操作符)匹配列表:

def listMatch(list:List[String]) = list match {
  case "Hello" :: Nil => println("the list only contain 'Hello'")
  case x :: y :: Nil => println("the list contain two value " + x + " and " + y)
  case "Hello" :: tail => println("the list contain many values " + list)
  case _ => println("the other list")
}

listMatch(List("Hello")) // the list only contain 'Hello'
listMatch(List("Hello", "World")) // the list contain two value Hello and World
listMatch(List("Hello", "World", "Yoona")) // the list contain many values List(Hello, World, Yoona)

同样也可以使用元组表示法匹配元组:

def pairMatch(t:Any) = t match {
  case ("Hello", _) => println("the first value is 'Hello'")
  case (x, "Hello") => println("the first value is " + x + " and the second value is 'Hello'")
  case _ => println("the other tuple")
}

pairMatch(("Hello", "World")) // the first value is 'Hello'
pairMatch(("World", "Hello")) // the first value is World and the second value is 'Hello'
pairMatch(("Hello", "World", "Yoona")) // the other tuple

6. 提取器

前面我们看到模式是如何匹配数组,列表和元组的,这些功能背后是提取器机制,带有从对象中提取值的unapply或unapplySeq方法的对象.unapply方法用于提取固定数量的对象,而unapplySeq提取的是一个序列.

arr match {
  case Array(0, x) => ...
  ...
}

Array伴生对象就是一个提取器,定义了一个unapplySeq方法.该方法被调用时,以被执行匹配动作的表达式作为参数.Array.unapplySeq(arr)产出一个序列的值,即数组中的值.第一个值与零进行比较,二第二个值被赋值给x.

正则表达式是另一个适合使用提取器的场景,如果正则表达式中有分组,可以使用提取器来匹配每个分组:

val pattern = "([0-9]+ ([a-z]+))".r
val str = "99 bottles"
str match {
  // num = 99 item = bottles
  case pattern(num, item) => ...
  ...
}

pattern.unapplySeq("99 bottles")生成一系列匹配分组的字符串,这些字符串分别赋值给变量num和item.

7. 变量声明中的模式

之前我们可以看到模式汇总是可以带变量的,同样我们也可以在变量声明中使用这样的模式:

// x = 1 y = 2
val (x, y) = (1, 2)

这对于使用那些返回对偶的函数是非常有用的:

val (q, r) = BigInt(10) /% 3
println("q value is " + q + " and r value is " + r)
// q value is 3 and r value is 1

备注

/%方法返回包含商和余数的对偶,而这两个值分别被变量q和r捕获到.

8. for表达式中的模式

可以在for推导表达式中使用带变量的模式.对于每一个遍历到的值,使用模式进行变量绑定:

import scala.collection.JavaConversions.propertiesAsScalaMap
for( (key, value) <- System.getProperties() ){
  println(key + " = " + value)
}

在for表达式中,失败的匹配将被跳过(不会抛出异常),下面循环打印出所有值为空白的键,跳过所有其他键:

import scala.collection.JavaConversions.propertiesAsScalaMap
for( (key, "") <- System.getProperties() ){
  println(key + " = ")
}

也可以使用守卫(注意if关键字出现在<-之后):

import scala.collection.JavaConversions.propertiesAsScalaMap
for( (key, value) <- System.getProperties() if value == ""){
  println(key + " = " + value)
}
版权声明:本文为博主原创文章,未经博主允许不得转载。

Scala学习笔记--模式匹配

Pattern matching(模式匹配) 1> 定义一个data常量,对它进行匹配,最后一行是_如果前面都不满足则匹配到他 2>在模式匹配中可以加入判断语句,进行选择 3>可以对...

scala学习笔记07--样本类(case class)和模式匹配

样本类:添加了case的类便是样本类。这种修饰符可以让Scala编译器自动为这个类添加一些语法上的便捷设定。如下:     1.添加与类名一致的工厂方法。也就是说,可以写成Var("x")来构造...

快学Scala学习笔记及习题解答(12-14高阶函数、集合、模式匹配和样例类)

本文Scala使用的版本是2.11.8第12章 高阶函数12.1 基本用法作为值得函数import scala.math._val num = 3.14 // ceil函数后的_表示这是个函数,而不是...

scala学习笔记(十三) 模式匹配与样例类

如果要问scala的核心类容是什么,以我接触的情况来看,模式匹配与样例 绝对是核心中的核心   因为scala是运行与JVM的,所以我们很多时候不自觉的会将他与java来进行比较,但是在这章之前它除了...
  • ymingw
  • ymingw
  • 2015年09月17日 16:14
  • 234

Scala学习笔记之模式匹配

Scala *模式匹配* (pattern matching)基于是否匹配某项条件来执行相应动作。本文以基本的示例代码来解释匹配表达式和匹配类型两种模式。...

Scala学习笔记19【Scala模式匹配入门实战】

1、Scala模式匹配入门package com.yl.Scalaobject ScalaTest { def main(args: Array[String]){ val number ...

Scala学习笔记21【Scala List之模式匹配实战】

package com.yl.Scalaobject ListTest { def main(args: Array[String]){ //声明方式1 val bigData = ...

Scala学习笔记20【Scala 模式匹配之case class实战】

简单来说,Scala的case class就是在普通的类定义前加case关键字,然后你可以对这些类来模式匹配。 case class带来的最大的好处是它们支持模式匹配。简单的case class 模...

快学Scala读书笔记之Chapter 14(模式匹配和样例类)

Scala有一个强大的模式匹配机制可以应用在多种场合:switch语句,类型查询,以及“析构”(获取复杂表达式的不同部分),除此以外Scala还提供了样例类,对模式匹配进行了优化。要点 match表达...

Scala School 笔记(三)--模式匹配与函数组合

函数组合 让我们创建两个函数: scala> def f(s: String) = "f(" + s + ")" f: (String)java.lang.String scala> def g(...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:[Scala]Scala学习笔记十 模式匹配
举报原因:
原因补充:

(最多只允许输入30个字)