scala pattern matching

scala pattern matching

pattern matching是用来检查一个值是否满足一个模式的机制。一个成功的匹配也可以解析出一个值变成它的组成部分(constituent parts)。这是一个比Java switch语句功能更强大的版本,它也同样能用在一系列if/else语句的地方。

语义Syntax

一个match表达式有一个值,一个match关键字和至少一个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之间的随机数。x变成match的左操作数,在右边是一个有四个case的表达式。最后一个case _ 是一个”捕获所有“的case,对于任意的大于2的数字。Cases也被称作选项。

 

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 class(Matching on case classes)

case class对于pattern matching特别有用。

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是一个抽象的超类,有三个具体的Notification类型,以case class Email,SMS和VoiceRecording来实现。现在我们可以在这些case class上进行pattern matching了。

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类型的参数,然后match Notification类型(举例来说:它找出这是否是一个Email、SMS或VoiceRecording)。在case Email(email, title, _),字段email和title在返回值时会使用,body被用_忽略了。

模式保护(Pattern guards)

pattern guard是简单的布尔表达式,用来让case更精确。只要在pattern后面加上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)中,只有当email在重要人士列表中时才会匹配。

只匹配类型(matching on type only)

你也可以像这样匹配一个类型:

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
}

 def goIdle根据Device类型的不同有不同的行为。这个在case需要在pattern上调用方法时很有用。这是一个约定:使用type的第一个字符作为case的标识符(这个case中的p和c)。

密封类(sealed classes)

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"
}

 这在pattern matching中很有有用,因为我们不需要catch all这个case。

 

注意

scala的pattern matching语句在通过case class来匹配代数类型时最有用。Scala也允许独立于case class的pattern定义,使用extractor objects的unapply方法(这里不太理解,需要看extractor object)。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值