Scala 模式匹配和样例类

mac2024-06-23  42

模式匹配和样例类

1模式匹配

Scala是没有Java中的switch case语法的,相对应的,Scala提供了更加强大的match case语法,即模式匹配,类替代switch case,match case也被称为模式匹配

Scala的match case与Java的switch case最大的不同点在于,Java的switch case仅能匹配变量的值,比1、2、3等;而Scala的match case可以匹配各种情况,比如变量的类型、集合的元素、有值或无值

match case的语法如下:变量 match { case 值 => 代码 }。如果值为下划线,则代表了不满足以上所有情况下的默认情况如何处理。此外,match case中,只要一个case分支满足并处理了,就不会继续判断下一个case分支了。(与Java不同,java的switch case需要用break阻止)

1.1 更好的switch

Scala中类似Java的switch代码:

注意:

Scala的模式匹配只会匹配到一个分支,不需要使用break语句,因为它不会掉入到下一个分支。 match是表达式,与if表达式一样,是有值的:

object PatternDemo {  def main(args: Array[String]): Unit = {    var sign = 0    val ch: Char  = 'p'    val valchar = 'p'    var digit = 0   //match 是表达式    ch match {      case '+' => sign = 1      case '-' => sign = -1      //使用|分割多个选项      case '*' | 'x' => sign = 2      //可以使用变量      case valchar => sign = 3      //case _ 类似Java中的default      // 如果没有模式能匹配,会抛出MacthError      //可以给模式添加守卫      case _ if Character.isDigit(ch) => digit = Character.digit(ch, 10)   }    println("sign = "+ sign) } }

1.2.类型匹配

Scala的模式匹配一个强大之处就在于,可以直接匹配类型,而不是值!!!这点是java的switch case绝对做不到的。

可以对表达式类型进行匹配:

 val arr = Array("hs", 1, 2.0, 'a')    val obj = arr(Random.nextInt(4))    println(obj)    obj match {      case x: Int => println(x)      case s: String => println(s.toUpperCase)      case _: Double => println(Int.MaxValue)      case _ => 0   }

注意: 当你在匹配类型的时候,必须给出一个变量名,否则你将会拿对象本身来进行匹配:

obj match {  case _: BigInt => Int.MaxValue  // 匹配任何类型为BigInt的对象  case BigInt => -1              // 匹配类型为Class的BigInt对象 }

匹配发生在运行期,Java虚拟机中泛型的类型信息是被擦掉的。因此,你不能用类型来匹配特定的Map类型。

case m: Map[String, Int] => ...   // error // 可以匹配一个通用的映射 case m: Map[_, _] => ...   // OK ​ // 但是数组作为特殊情况,它的类型信息是完好的,可以匹配到Array[Int] case m: Array[Int] => ...   // OK

1.3 匹配字符串、数组、列表、元组

字符串匹配

/**  * 模式匹配-字符串  */ object MatchString {  def main(args: Array[String]): Unit = {    val arr = Array("asan", "jiangzi", "gulingling", "zhenshauang")    val name = arr(Random.nextInt(arr.length))    println(name)    name match {      case "zhoudongyu" => println("阿三")      case "yangzi" => println("酱紫")      case "guanxiaotong" => println("孤零零")      case "zhengshuang" => println("真爽")      case _ => println("Nothing ...")   } } }

数组匹配

对Array进行模式匹配,分别可以匹配带有指定元素的数组、带有指定个数元素的数组、以某元素打头的数组.

val arr1 = Array(1,1)  val res = arr1 match {  case Array(0) => "0"  //匹配包含0的数组  case Array(x, y) => s"$x $y"  // 匹配任何带有两个元素的数组,并将元素绑定到x和y  case Array(0, _*) => "0..."  //匹配任何以0开始的数组  case _ => "something else" }

列表匹配

val lst = List(1,2) val res2 =  list match {   case 0 :: Nil => "0"   case x :: y :: Nil => x + " " + y   case 0 :: tail => "0 ..."   case _ => "something else" }

元组匹配

var pair = (1,2) val res3 =  pair match {  case (0, _)  => "0 ..."  case (y, 0) => s"$y 0"  case _ => "neither is 0" }

1.4 样例类

在Scala中样例类是一中特殊的类,样例类是不可变的,

可以通过值进行比较,可用于模式匹配。

定义一个样例类:

构造器中每一个参数都是val,除非显示地声明为var

伴生对象提供apply ,让你不使用new关键字就能构造出相应的对象

case class Point(x: Int, y: Int)

创建样例类对象:

val point = Point(1, 2) val anotherPoint = Point(1, 2) val yetAnotherPoint = Point(2, 2) //访问对象值 point.x point.x =1 //不可以

通过值对样例类对象进行比较:

if (point == anotherPoint) {  println(point + " and " + anotherPoint + " are the same.") } else {  println(point + " and " + anotherPoint + " are different.") } // Point(1,2) 和 Point(1,2)一样的. ​ if (point == yetAnotherPoint) {  println(point + " and " + yetAnotherPoint + " are the same.") } else {  println(point + " and " + yetAnotherPoint + " are different.") } // Point(1,2)和Point(2,2)是不同的.

在模式匹配中使用样例类:

样例类是一种特殊的类,可用于模式匹配,case class是多例的,后面要跟构造参数,case object是单例的。

object CaseClassMatch {  //定义样例类  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(email, title, _) =>        s"You got an email from $email 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"   } } def main(args: Array[String]): Unit = {  val someSms = SMS("12345", "Are you there?")  val someVoiceRecording = VoiceRecording("Tom", "voicerecording.org/id/123")  println(showNotification(someSms)) //结果: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 } }

声明样例类 ,以下几件事会自动发生:

提供unapply方法,让模式匹配可以工作

生成toString equals hashCode copy 方法,除非显示给出这些方法的定义。

1.5 Option类型

在Scala中Option类型样例类用来表示可能存在或也可能不存在的值(Option的子类有Some和None)。Some包装了某个值,None表示没有值。

object OptionDemo {  def main(args: Array[String]) {    val map = Map("a" -> 1, "b" -> 2)    val v = map.get("b") match {      case Some(i) => i      case None => 0   }    println(v)    //更好的方式    val v1 = map.getOrElse("c", 0)    println(v1) } }

1.6 偏函数

被包在花括号内没有match的一组case语句是一个偏函数,它是PartialFunction[A, B]的一个实例,A代表参数类型,B代表返回类型,常用作输入模式匹配

一个是apply()方法,直接调用可以通过函数体内的case进行匹配,返回结果; 另一个是isDefinedAt()方法,可以返回一个输入,是否跟任何一个case语句匹配

object PartialFunctionDemo {  def f1: PartialFunction[String, Int] = {    case "one" => 1    case "two" => 2    case _ => -1 } ​  def main(args: Array[String]) {    //调用f.apply("one")    println(f1.apply("one"))    println(f1("one"))    println(f1.isDefinedAt("three"))    //抛出MatchError    println(f1("three")) } }

 

最新回复(0)