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

  • 相关阅读:
    HDU 2196 Computer
    HDU 1520 Anniversary party
    POJ 1217 FOUR QUARTERS
    POJ 2184 Cow Exhibition
    HDU 2639 Bone Collector II
    POJ 3181 Dollar Dayz
    POJ 1787 Charlie's Change
    POJ 2063 Investment
    HDU 1114 Piggy-Bank
    Lca hdu 2874 Connections between cities
  • 原文地址:https://www.cnblogs.com/chuijingjing/p/14451025.html
Copyright © 2011-2022 走看看