scala的模式匹配

简介: scala提供了一个非常强大的模式匹配机制,那什么是模式匹配呢?模式匹配是检查某个值(value)是否匹配某一个模式的机制,一个成功的匹配同时会将匹配值解构为其组成部分。它是Java中的switch语句的升级版,同样可以用于替代一系列的 if/else 语句。语法

scala提供了一个非常强大的模式匹配机制,那什么是模式匹配呢?模式匹配是检查某个值(value)是否匹配某一个模式的机制,一个成功的匹配同时会将匹配值解构为其组成部分。它是Java中的switch语句的升级版,同样可以用于替代一系列的 if/else 语句。


语法


一个模式匹配包含了一系列备选项,每个都开始于关键字 case。每个备选项都包含了一个模式及一到多个表达式。箭头符号 => 隔开了模式和表达式。


以下是一个简单的整型值模式匹配实例:


import scala.util.Random
val x: Int = Random.nextInt(10)
x match {
  case 0 => "zero"
  case 1 => "one"
  case 2 => "two"
  case _ => "many"
}


上述代码中的val x是一个0到10之间的随机整数,将它放在match运算符的左侧对其进行模式匹配,match的右侧是包含4条case的表达式,其中最后一个case _表示匹配其余所有情况,在这里即是x大于2的情况。


match表达式具有一个结果值:


def matchTest(x: Int): String = x match {
  case 1 => "one"
  case 2 => "two"
  case _ => "many"
}
matchTest(3)  // many
matchTest(1)  // one


这个match表达式是String类型的,因为所有的情况(case)均返回String,所以matchTest函数的返回值是String类型。


案例类(case classes)的匹配


案例类非常适合用于模式匹配。看下面的代码


abstract class Notification
case class Email(sender: String, title: String, body: String) extends Notification
case class SMS(caller: String, message: String) extends Notification
case class VoiceRecording(contactName: String, link: String) extends Notification


Notification 是一个抽象类,它有三个具体的子类Email, SMS和VoiceRecording,我们可以在这些案例类(Case Class)上像这样使用模式匹配:


def showNotification(notification: Notification): String = {
  notification match {
    case Email(email, title, _) =>
      s"You got an email from $email with title: $title"
    case SMS(number, message) =>
      s"You got an SMS from $number! Message: $message"
    case VoiceRecording(name, link) =>
      s"you received a Voice Recording from $name! Click the link to hear it: $link"
  }
}
val someSms = SMS("12345", "Are you there?")
val someVoiceRecording = VoiceRecording("Tom", "voicerecording.org/id/123")
println(showNotification(someSms))  // prints You got an SMS from 12345! Message: Are you there?
println(showNotification(someVoiceRecording))  // you received a Voice Recording from Tom! Click the link to hear it: voicerecording.org/id/123


showNotification函数接受一个抽象类Notification对象作为输入参数,然后匹配其具体类型。(也就是判断它是一个Email,SMS,还是VoiceRecording)。在case Email(email, title, _)中,对象的email和title属性在返回值中被使用,而body属性则被忽略,故使用_代替。


模式守卫(Pattern gaurds)


为了让匹配更加具体,可以使用模式守卫,也就是在模式后面加上if <boolean expression>。


def showImportantNotification(notification: Notification, importantPeopleInfo: Seq[String]): String = {
  notification match {
    case Email(email, _, _) if importantPeopleInfo.contains(email) =>
      "You got an email from special someone!"
    case SMS(number, _) if importantPeopleInfo.contains(number) =>
      "You got an SMS from special someone!"
    case other =>
      showNotification(other) // nothing special, delegate to our original showNotification function
  }
}
val importantPeopleInfo = Seq("867-5309", "jenny@gmail.com")
val someSms = SMS("867-5309", "Are you there?")
val someVoiceRecording = VoiceRecording("Tom", "voicerecording.org/id/123")
val importantEmail = Email("jenny@gmail.com", "Drinks tonight?", "I'm free after 5!")
val importantSms = SMS("867-5309", "I'm here! Where are you?")
println(showImportantNotification(someSms, importantPeopleInfo))
println(showImportantNotification(someVoiceRecording, importantPeopleInfo))
println(showImportantNotification(importantEmail, importantPeopleInfo))
println(showImportantNotification(importantSms, importantPeopleInfo))


在case Email(email, _, _) if importantPeopleInfo.contains(email)中,除了要求notification是Email类型外,还需要email在重要人物列表importantPeopleInfo中,才会匹配到该模式。


仅匹配类型


也可以仅匹配类型,如下所示:


abstract class Device
case class Phone(model: String) extends Device{
  def screenOff = "Turning screen off"
}
case class Computer(model: String) extends Device {
  def screenSaverOn = "Turning screen saver on..."
}
def goIdle(device: Device) = device match {
  case p: Phone => p.screenOff
  case c: Computer => c.screenSaverOn
}


当不同类型对象需要调用不同方法时,仅匹配类型的模式非常有用,如上代码中goIdle函数对不同类型的Device有着不同的表现。一般使用类型的首字母作为case的标识符,例如上述代码中的p和c,这是一种惯例。


密封类


特质(trait)和类(class)可以用sealed标记为密封的,这意味着其所有子类都必须与之定义在相同文件中,从而保证所有子类型都是已知的。


sealed abstract class Furniture
case class Couch() extends Furniture
case class Chair() extends Furniture
def findPlaceToSit(piece: Furniture): String = piece match {
  case a: Couch => "Lie on the couch"
  case b: Chair => "Sit on the chair"
}


这对于模式匹配很有用,因为我们不再需要一个匹配其他任意情况的case。


注意,在声明样例类时,下面的过程自动发生了:


(1)构造器的每个参数都成为val,除非显式被声明为var,但是并不推荐这么做;


(2)在伴生对象中提供了apply方法,所以可以不使用new关键字就可构建对象;


(3)提供unapply方法使模式匹配可以工作;


(4)生成toString、equals、hashCode和copy方法,除非显示给出这些方法的定义。


相关文章
|
10月前
|
Scala
166 Scala 模式匹配和样例类
166 Scala 模式匹配和样例类
68 0
|
2月前
|
Scala 开发者
Scala中的模式匹配与高阶函数:探索强大的编程范式
【7月更文挑战第11天】Scala中的模式匹配和高阶函数是两种极其强大的特性,它们不仅提升了代码的表达力和可读性,还使得开发者能够编写出更加灵活和可重用的解决方案。通过
|
3月前
|
Scala
scala-模式匹配(字符串、数组、元组、集合、类、偏函数)
scala-模式匹配(字符串、数组、元组、集合、类、偏函数)
19 0
|
4月前
|
Scala
Scala中的异常处理和模式匹配
Scala中的异常处理和模式匹配
36 1
|
4月前
|
Scala
Scala中的模式匹配:强大的匹配和转换工具
Scala中的模式匹配:强大的匹配和转换工具
34 1
|
4月前
|
分布式计算 Java 大数据
Scala:样例类、模式匹配、Option、偏函数、泛型(三)
Scala:样例类、模式匹配、Option、偏函数、泛型(三)
66 0
|
Java 大数据 Scala
大数据开发基础的编程语言的Scala的模式匹配和正则
Scala是一种支持模式匹配和正则表达式的编程语言,它提供了强大的字符串处理和数据解析功能。本文将介绍Scala中模式匹配和正则表达式的概念和用法,帮助开发者更好地理解和应用这门语言。
71 0
|
安全 Java 编译器
Scala快速入门-10-模式匹配与样例类
mathch表达式是一个更好的switch,不会有穿透到下一个分支的问题 如果没有模式能够匹配,会抛出MatchError,可以用case _ 模式来避免,相当于Java中的default 模式可以包含一个随意定义的条件,称做守卫 可以匹配数组、列表、元组等模式,然后将匹配到不同部分绑定到变量 样例类及密封类的模式匹配 用Option来存放可能存在也可能不存在的值,比null更安全
|
分布式计算 Java Scala
scala中的模式匹配和样例类
scala有一个十分强大的模式匹配机制,可以应用到很多场合。java switch caseswitch语句类型查询以及快速获取数据并且scala还提供了样例类,对模式匹配进行了优化,可以快速进行匹配。
84 0
scala中的模式匹配和样例类
|
存储 搜索推荐 算法
Flink / Scala - DataStream Broadcast State 模式示例详解
一.引言 上一篇文章Flink / Scala - DataSet 应用 Broadcast Variables介绍了 DataSet 场景下 Broadcast 的使用,这一边
546 0
Flink / Scala - DataStream Broadcast State 模式示例详解