zoukankan      html  css  js  c++  java
  • scala之旅-核心语言特性【模式匹配】(十四)

    模式匹配是一个检查值是否属于某个模式的机制。成功的匹配可以将一个值分解成多个组成部分。它相当于java中的switch的一个强化版本,并且可以代替if/else的很多场景。

    语法

    一个匹配表达式有一个值,然后接一个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"
    }

    上面的 val x 是一个间于0到10的整型随机数。x 成为操作符 match 左边操作的对象,右边则是4个case 表达式。最后一个 case _ 是一个用来捕获其他所有Int值的。 case 也可以有选择地进行调用。

    匹配表达式有一个值。

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

    这个匹配表达式是String类型,因为它的所有的case 都是返回的String类型。因为函数 matchTest返回一个String 类型。

    case类中匹配

    case 类在模式匹配中尤为的友好。

    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 是一个抽象超类,他一个三个具体的case子类实现类它: Email ,SMS 和 VoiceRecording。 现在我们用这些case类型进行模式匹配:

    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))  // prints You received a Voice Recording from Tom! Click the link to hear it: voicerecording.org/id/123

    方法 showNotification 传递一个Notification抽象类作为形参,然后匹配Notification类型(通过识别出它是Email,SMS还是VoiceRecording)。在 case Email(sender,title,_) 中,属性sender和title被用到了返回值里面,但是 body属性被一个 _ 忽略了。

    模式监视

    模式监视是一个简单的布尔表达式,一般被用来让case 更加明确。 只需要添加 if <布尔表达式> 在模式后面。

    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("123-4567", "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)) // prints You got an SMS from 123-4567! Message: Are you there?
    println(showImportantNotification(someVoiceRecording, importantPeopleInfo)) // prints You received a Voice Recording from Tom! Click the link to hear it: voicerecording.org/id/123
    println(showImportantNotification(importantEmail, importantPeopleInfo)) // prints You got an email from special someone!
    
    println(showImportantNotification(importantSms, importantPeopleInfo)) // prints You got an SMS from special someone!

    在 case Email(sender,_,_) if importantPeopleInfo.contains(sender) 中,只有当 sender 在重要人列表中才进行匹配。

    只做类型匹配

    你可以像下面这样进行匹配:

    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的类型会有一个不同行为。这个可以让你在一个模式匹配中根据类型调用对应方法。在匹配前面用标志符可以很简便的进行使用(这里用的p和c做的标志符)

    sealed密封类

    特性和类可以用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"
    }

    这在模式匹配中很有用,因为我们不需要再用一个默认值捕捉其他的类型了。 

    笔记

    Scala的模式匹配语句对于通过case类表示的代数类型最为有用。Scala还允许使用unapply和方法中对象提取器进行定义独立的case类型进行模式匹配

  • 相关阅读:
    操作系统与进程.md
    解决粘包现象
    Python3网络爬虫开发实战
    Django学习目录
    前端学习目录
    MySQL数据库学习目录
    第一章 开发环境配置
    15.3 Scrapyd 对接 Docker
    13.4 Spider 的用法
    9.1 代理的设置
  • 原文地址:https://www.cnblogs.com/zhouwenyang/p/13890157.html
Copyright © 2011-2022 走看看