定义
模式匹配是检查某个值(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