Scala模式匹配

定义

模式匹配是检查某个值(value)是否匹配某一个模式的机制,一个成功的匹配同时会将匹配值解构为其组成部分。它是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之间的随机整数,将它放在match运算符的左侧对其进行模式匹配,match的右侧是包含4条case的表达式,其中最后一个case _表示匹配其余所有情况,在这里就是其他可能的整型值。

变量模式匹配

def main(args: Array[String]): Unit = {
    println(patternShow(3))
    println(patternShow("three"))
    println(patternShow(10))
  }
  def patternShow(x:Any) = x match {
    case x if (x==3) => x
    case x if (x=="three") => x
    case _ => 0
  }
  

类型模式匹配

object Test {
  def main(args: Array[String]): Unit = {
    println(typePattern(1))
    println(typePattern("123"))
    println(typePattern(3.14))
    println(typePattern('+'))
  }
  def typePattern(tp:Any) = tp match {
    case tp : Int => tp
    case tp : String => Integer.parseInt(tp)
    case tp : Double => "Double"
    case _ => 0
  }
}

序列化模式

序列化模式用于匹配如数组Array、列表List、Range这样的线性结构集合,其实原理也是通过case class起作用的。

def main(args: Array[String]): Unit = {
    val arr = Array("Spark","SparkSql","SparkStreaming")
    val list = List("Spark","Hive","SparkSql")
    println(sequencePattern(arr))
    println(sequencePattern(list))
  }
  
  def sequencePattern(p:Any) = p match {
    //序列模式匹配,_*表示匹配剩余内容,first、second匹配数组p中的第一、二个元素
    case Array(first,second,_*) => first + "," + second
    //_匹配数组p的第一个元素,但不赋给任何变量
    case List(_,second,_*) => second
    case _ => "Other"
  }

元组模式

元组模式用于匹配scala中的元组内容,用于匹配元组类型的变量内容。

  def main(args: Array[String]): Unit = {
    val a = ("Spark","Hive","Flume")
    println(tuplePattern(a))    //Spark
    val list = List("Spark","Hive","Flume")
    println(tuplePattern(list))    //other
  }
  def tuplePattern(t:Any) = t match {
    case (one,_,_) => one
    case _ => "Other"
  }

变量绑定模式

  def main(args:Array[String]) :Unit = {
    var t = List(List(1, 2, 3), List(2, 3, 4))
    println(variableBindingPattern(t))
    var t1 = List(List(1, 2), List(2, 3))
    println(variableBindingPattern(t1))
  }

  def variableBindingPattern(t: Any) = t match
  {
    //变量绑定,采用变量名(这里是e)
    //与@符号,如果后面的模式匹配成功,则将整体匹配结果作为返回值
      case List (_, e@List (_, _, _) ) => e
      case _ => Nil
  }

构造器模式匹配

def main(args: Array[String]): Unit = {
    val p = Person("Tom",20)
    println(constructorPattern(p))
  }
  case class Person(name:String,age:Int)
  def constructorPattern(p:Person) = p match {
    case Person(name,age) => "name=" +name+ ",age=" +age
    case Person(name,_) => "name=" +name
    case Person(_,age) => "age=" +age
    case _ => "Other"
  }
  
def main(args: Array[String]): Unit = {
    val sms = SMS("Tom","today is sunday")
    println(showNotification(sms))

    val voiceRecording = VoiceRecording("Jerry", "voicerecording.org/id/123")
    println(showNotification(voiceRecording))

  }
 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

  def showNotification(notification:Notification):String = {
    notification match{
      case Email(sender,title,_) => s"You got an email from $sender with title:$title"
      case SMS(caller,message) => s"You got an SMS from $caller with Message:$message"
      case VoiceRecording(name,link) => s"You got an VoiceRecording from $name with link:$link"
    }
  }

模式守卫

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

def main(args: Array[String]): Unit = {
    val importantPeopleInfo = Seq("100-1000", "jenny@gmail.com")

    val someSms = SMS("100-1000", "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("100-1000", "I'm here! Where are you?")

    println(showImportantNotification(someSms, importantPeopleInfo))
    println(showImportantNotification(someVoiceRecording, importantPeopleInfo))
    println(showImportantNotification(importantEmail, importantPeopleInfo))
    println(showImportantNotification(importantSms, importantPeopleInfo))

  }
  
  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

  def showNotification(notification:Notification):String = {
    notification match{
      case Email(sender,title,_) => s"You got an email from $sender with title:$title"
      case SMS(caller,message) => s"You got an SMS from $caller with Message:$message"
      case VoiceRecording(name,link) => s"You got an VoiceRecording from $name with link:$link"
    }
  }

  def showImportantNotification (notification:Notification, importantPeopleInfo:Seq[String]):String = {
    notification match {
      case Email(sender,_,_) if importantPeopleInfo.contains(sender)
      => s"You got an important email from important people :$sender "
      case SMS(caller,_) if importantPeopleInfo.contains(caller) 
      => s"You got an important SMS from important people: $caller "
      case other => showNotification(other)
    }
  }

密封类

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

def main(args: Array[String]): Unit = {
    val couch = Couch()
    println(findPlaceToSit(couch))
  }
  sealed abstract class Furniture
  case class Couch() extends Furniture
  case class Chair() extends Furniture
  def findPlaceToSit(place:Furniture):String = place match {
    case a:Couch => "lie on the couch"
    case b:Chair => "sit on the chair"
  }

参考

https://docs.scala-lang.org/zh-cn/tour/pattern-matching.html

https://www.cnblogs.com/zlslch/p/6115392.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值