您的位置:首页 > 汽车 > 新车 > 详解 Scala 的模式匹配

详解 Scala 的模式匹配

2025/1/8 13:03:29 来源:https://blog.csdn.net/weixin_44480009/article/details/139244921  浏览:    关键词:详解 Scala 的模式匹配

一、基本语法

Scala 中的模式匹配类似于 Java 中的 switch 语法,但是功能更强大

/**[var a = / def func() = ] var_name match {case value1 => statement1case value2 => statement2case value3 => statement3case _ => defaultOP}
*/
object TestMatchCase {def main(args: Array[String]): Unit = {val a = 10val b = 20def matchCalculate(op: Char): Any = op match {case '+' => a + bcase '-' => a - bcase '*' => a * bcase '/' => a / bcase _ => "非法运算符"}println(matchCalculate('+'))println(matchCalculate('*'))println(matchCalculate('@'))}
}
  • 如果所有 case 都不匹配,那么会执行 case _ 分支,类似于 Java 中 default 语句,若此时没有 case _ 分支,那么会抛出 MatchError
  • 每个 case 中,不需要使用 break 语句,会自动中断 case
  • match case 语句可以匹配任何类型,而不只是字面量
  • => 后面的代码块,直到下一个 case 语句之前的代码是作为一个整体执行,可以使用 {} 括起来,也可以省略

二、模式守卫

在模式匹配中增加条件守卫可以匹配某个范围的数据

object TestMatchGuard {def main(args: Array[String]): Unit = {// 使用模式守卫实现绝对值def abs(num: Int): Int = {num match {case i: Int if i >= 0 => icase i: Int if i < 0 => -i}}println(abs(22))println(abs(0))println(abs(-18))}
}

三、模式匹配类型

1. 匹配常量

模式匹配可以匹配所有的字面量,包括字符串,字符,数字,布尔值等

object TestMatchTypes {def main(args: Array[String]): Unit = {def describe(x: Any): String = x match {case 1 => "Int one"case "hello" => "String hello"case true => "Boolean true"case '+' => "Char +"case _ => ""  // _ 是占位符,可以用其他字符替代}println(describe(1))println(describe("hello"))println(describe(0.3))}
}

2. 匹配类型

模式匹配可以实现类似 isInstanceOf[T] 和 asInstanceOf[T] 的功能

object TestMatchTypes {def main(args: Array[String]): Unit = {def describeType(x: Any): String = x match {case i: Int => "Int " + icase s: String => "String " + scase list: List[String] => "List " + listcase array: Array[Int] => "Array[Int] " + array.mkString(",")case a => "other type " + a  // 用 _ 占位不能获取到传入的变量,可以用其他字符替代}println(describeType(1))println(describeType("hello"))println(describeType(List("hello", "scala")))println(describeType(List(2, 3))) // 可以匹配,scala 会做泛型擦除println(describeType(Array("hello", "scala"))) // 不能匹配,Array 没有泛型擦除println(describeType(Array(2, 3)))}
}

3. 匹配数组

模式匹配可以对集合进行精确的匹配,例如匹配只有两个元素的、且第一个元素为 0 的数组

object TestMatchTypes {def main(args: Array[String]): Unit = {val arrList: List[Array[Any]] = List(Array(0),Array(1, 0),Array(0, 1, 0),Array(1, 1, 0),Array(2, 3, 7 ,15),Array("hello", 20, 30))for(arr <- arrList) {var result = arr match {case Array(0) => "只有一个元素为 0 的数组"case Array(x, y) => "有两个元素的数组:" + x + ", " + ycase Array(0, _*) => "第一个元素为 0 的数组"case Array(x, 1, y) => "中间元素为 1 的三元素数组"case _ => "other type"}println(result)}}
}

4. 匹配列表

4.1 方式一
object TestMatchTypes {def main(args: Array[String]): Unit = {val lists: List[List[Any]] = List(List(0),List(1, 0),List(0, 0, 0),List(1, 1, 0),List(1, 0, 0),List(88),List("hello"))for(list <- lists) {var result = list match {case List(0) => "只有一个元素为 0 的列表"case List(x, y) => "有两个元素的列表:" + x + ", " + ycase List(0, _*) => "第一个元素为 0 的列表"case List(x, 1, y) => "中间元素为 1 的三元素列表"case List(a) => "只有一个元素的列表:" + acase _ => "other type"}println(result)}}
}
4.2 方式二
object TestMatchTypes {def main(args: Array[String]): Unit = {val list1 = List(1, 2, 3, 4, 5)val list2 = List(5)// first:1 second:2 rest:List(3, 4, 5)list1 match {case first :: second :: rest => println(s"first:$first second:$second rest:$rest") // 匹配有第一个和第二个元素的列表case _ => println("other type")}// other typelist2 match {case first :: second :: rest => println(s"first:$first second:$second rest:$rest")case _ => println("other type")}}
}

5. 匹配元组

object TestMatchTypes {def main(args: Array[String]): Unit = {val tupleList = List((0),(0, 1),(1, 1),(0, 0, 1),(1, 1, 0),("hello", true, 0.5))for(tuple <- tupleList) {val result = tuple match {case (0) => "只有一个元素 0 的元组"case (0, _) => "第一个元素为 0 的二元组"case (x, y) => "二元组:" + x + ", " + ycase (a, 1, _) => "中间元素为 1 的三元组:" + acase (a, b, c) => s"三元组:$a $b $c"case _ => "other type"}println(result)}}
}

6. 匹配对象及样例类

6.1 自定义实现
// 定义一个类
class Student(val name: String, val age: Int)// 定义伴生对象
object Student {// 实现 apply 方法用于创建对象def apply(name: String, age: Int): Student = new Student(name, age)// 实现 unapply 方法用于拆解对象属性def unapply(student: Student): Option[(String, Int)] = { // Option 防止空指针if(student == null) {None} else {Some((student.name, student.age))}}
}object TestMatchObject {def main(args: Array[String]): Unit = {// 创建对象val student = new Student("tom", 18)// 对象模式匹配val result = student match { // 对象匹配的是各属性是否相同而不是地址// 不能使用 new 创建,且类的伴生对象必须实现 apply 和 unapply 方法case Student("tom", 18) => "tom 18" case _ => "other"}println(result)}
}
  • Student("tom", 18) 在执行时,实际调用的是伴生对象中的 apply 方法构造出相应的对象
  • Student("tom", 18) 写在 case 后时会默认调用伴生对象中的 unapply 方法(对象提取器),该对象作为 unapply 方法的参数,在 unapply 方法中将该对象的 name 和 age 属性提取出来,与 new Student("tom", 18) 中的属性值进行匹配
  • 只有当 case 中对象的 unapply 方法(提取器)返回 Some,且所有属性均一致,才算匹配成功;若属性不一致,或返回 None,则匹配失败
  • 若只提取对象的一个属性,则提取器为 unapply(obj: ObjClass): Option[T];若提取对象的多个属性,则提取器为 unapply(obj: ObjClass): Option[(T1,T2,T3…)];若提取对象的可变个属性,则提取器为 unapplySeq(obj: ObjClass): Option[Seq[T]]
6.2 样例类实现
  • 样例类简介

    /**定义语法:case class className(field1: type1, field2: type2,...)特点:1.样例类仍然是类,和普通类相比,只是自动生成了伴生对象且伴生对象中自动提供了一些常用的方法,如 apply、 unapply、 toString、 equals、 hashCode 和 copy2.样例类是为模式匹配而优化的类,因为其默认提供了 unapply 方法,因此,样例类可以直接使用模式匹配,而无需自己实现 unapply 方法。3.构造器中的每一个参数默认都为 val,除非它被显式地声明为 var(不建议这样做)
    */
    case class User(name: String, age: Int) // 无需指定 val
    
  • 实现对象模式匹配

    // 定义样例类
    case class User(name: String, age: Int)object TestMatchObject {def main(args: Array[String]): Unit = {val user = User("bob", 20)val result = user match {case User("bob", 20) => "bob 20"case _ => "other"}println(result)}
    }
    

四、变量声明模式匹配

object TestMatchVariable {def main(args: Array[String]): Unit = {// 使用模式匹配元组变量赋值val (x, y, z) = (10, "hello", true)println(s"x:$x y:$y z:$z")// 使用模式匹配列表变量赋值val List(first, second, _*) = List(2, 4, 7, 9)println(s"first:$first second:$second")val fir :: sec :: rest = List(2, 4, 7, 9)println(s"fir:$fir sec:$sec rest:$rest") // fir:2 sec:4 rest:List(7, 9)// 使用模式匹配对象属性赋值val Person(name, age) = Person("zhangsan", 16)println(s"name=$name age=$age")}
}

五、for循环模式匹配

object TestMatchFor {def main(args: Array[String]): Unit = {val list: List[(String, Int)] = List(("a", 1), ("b", 4), ("c",3), ("a",4))// 1. for循环直接赋值 KVfor((k, v) <- list) { // (elem <- list)println(k + ": " + v) // println(elem._1 + ": " + elem._2)}// 2. for循环只遍历 key 或 valuefor((k, _) <- list) { // ((_, v) <- list)println(k) // println(v)}// 3. for循环遍历指定 key 或 valuefor(("a", v) <- list) { // ((k, 4) <- list)println("a: " + v) // println(k + ": 4")}}
}

六、偏函数模式匹配

偏函数也是函数的一种,通过偏函数我们可以方便的对输入参数做更精确的检查

1. 偏函数定义

/**val funcName: PartialFunction[inParamClass, outParamClass] = {case value => statement}
*/
// 定义一个获取列表第二个元素的偏函数
val getSecond: PartialFunction[List[Int], Option[Int]] = {case first :: second :: _ => Some(second)
}

2. 偏函数原理

// 1. 定义的偏函数会被解析翻译
val getSecond: PartialFunction[List[Int], Option[Int]] = {case first :: second :: _ => Some(second)
}
// =>
val getSecond = new PartialFunction[List[Int], Option[Int]] {//检查输入参数是否合格override def isDefinedAt(list: List[Int]): Boolean = list match {case first :: second :: _ => truecase _ => false}//执行函数逻辑override def apply(list: List[Int]): Option[Int] = list match {case first :: second :: _ => Some(second)}
}// 2. 偏函数调用时采用 applyOrElse 方法,其逻辑为 if(ifDefinedAt(list)) apply(list) else default。如果输入参数满足条件,即 isDefinedAt 返回 true,则执行 apply 方法,否则执行 defalut 方法,default 方法为参数不满足要求的处理逻辑
getSecond.applyOrElse(List(1,2,3), (_: List[Int]) => None)

3. 应用案例

object TestPartialFunction {def main(args: Array[String]): Unit = {// 使用偏函数实现绝对值方法val positiveAbs: PartialFunction[Int, Int] = {case x if x > 0 => x}val negativeAbs: PartialFunction[Int, Int] = {case x if x < 0 => -x}val zeroAbs: PartialFunction[Int, Int] = {case 0 => 0}def abs(x: Int): Int = (positiveAbs orElse negativeAbs orElse zeroAbs)(x)println(abs(-22))println(abs(18))println(abs(0))}
}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com