zoukankan      html  css  js  c++  java
  • Scala 模式匹配

    模式匹配是检查某个值(value)是否匹配某一个模式的机制,一个成功的匹配同时会将匹配值解构为其组成部分。

    它是Java中的switch语句的升级版,同样可以用于替代一系列的 if/else 语句。

    Scala的模式匹配语句对于使用案例类(case classes)表示的类型非常有用,

    同时也可以利用提取器对象(extractor objects)中的unapply方法来定义非案例类对象的匹配。

    语法

    一个模式匹配语句包括一个待匹配的值,match关键字,以及至少一个case语句。

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

    案例类(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 是一个虚基类,它有三个具体的子类EmailSMSVoiceRecording

    我们可以在这些案例类(Case Class)上像这样使用模式匹配:

    def showNotification(notification: Notification): String = {
      notification match {
        case Email(sender, title, _) =>
          s"You got an email from $sender 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对象作为输入参数,然后匹配其具体类型。(也就是判断它是一个EmailSMS,还是VoiceRecording)。

    case Email(sender, title, _)中,对象的sendertitle属性在返回值中被使用,而body属性则被忽略,故使用_代替。

    模式守卫(Pattern gaurds)

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

    def showImportantNotification(notification: Notification, importantPeopleInfo: Seq[String]): String = {
      notification match {
        case Email(sender, _, _) if importantPeopleInfo.contains(sender) =>
          "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(sender, _, _) if importantPeopleInfo.contains(sender)中,除了要求notificationEmail类型外,

    还需要sender在重要人物列表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的标识符,例如上述代码中的pc,这是一种惯例。

    密封类

    特质(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

  • 相关阅读:
    SQL 运算符
    Shiro 入门
    SSM 整合配置
    MyBatis 入门
    Git 常用命令
    JSP
    Servlet
    Oracle 基础
    JDBC
    Java Thread
  • 原文地址:https://www.cnblogs.com/chuijingjing/p/14451025.html
Copyright © 2011-2022 走看看