前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Scala 高阶(九):Scala中的模式匹配

Scala 高阶(九):Scala中的模式匹配

作者头像
百思不得小赵
发布2022-12-01 14:47:58
1.5K0
发布2022-12-01 14:47:58
举报
文章被收录于专栏:小赵Java总结

大家好,我是百思不得小赵。

创作时间:2022 年 7 月 21 日 博客主页: 🔍点此进入博客主页 —— 新时代的农民工 🙊 —— 换一种思维逻辑去看待这个世界 👀


文章目录


本次主要分享Scala中关于模式匹配的内容,Scala中的模式匹配类似于Java中的switch语法,但是Scala在基于Java的思想上补充了特有的功能。

一、概述

基本语法

代码语言:javascript
复制
value match {
    case caseVal1 => returnVal1
    case caseVal2 => returnVal2
    ...
    case _ => defaultVal
}

模式匹配语法中,采用 match 关键字声明,每个分支采用 case 关键字进行声明,当需 要匹配时,会从第一个 case 分支开始,如果匹配成功,那么执行对应的逻辑代码,如果匹 配不成功,继续执行下一个分支进行判断。如果所有 case 都不匹配,那么会执行 case _分支,类似于 Java 中 default 语句。

举个例子:

代码语言:javascript
复制
  val x: Int = 2
    val y: String = x match {
      case 1 => "one"
      case 2 => "two"
      case 3 => "three"
      case _ => "other"
    }

第二个例子:

代码语言:javascript
复制
    // 示例:使用模式匹配实现简单的二元运算
    val a = 25
    val b = 21

    def matchOualop(op: Char) = op match {
      case '+' => a + b
      case '-' => a - b
      case '*' => a * b
      case '/' => a / b
      case _ => "非法运算"
    }

    println(matchOualop('+'))
    println(matchOualop('-'))
    println(matchOualop('\\'))
  • 如果所有 case 都不匹配,那么会执行 case _ 分支,类似于 Java 中 default 语句,若此时没有 case _ 分支,那么会抛出 MatchError
  • 每个 case 中,不需要使用 break 语句,自动中断 case
  • match case 语句可以匹配任何类型,而不只是字面量。
  • => 后面的代码块,直到下一个 case 语句之前的代码是作为一个整体执行,可以使用{}括起来,也可以不括。

二、模式守卫

需要进行匹配某个范围的数据内容的时候,可以在模式匹配中进行模式守卫的操作,类似于for推倒式中的循环守卫。

举个例子:

代码语言:javascript
复制
object Test01_PatternMatchBase {
  def main(args: Array[String]): Unit = {
    // 模式守卫
    // 求一个整数的绝对值
    def abs(num: Int) = num match {
      case i if i >= 0 => i
      case i if i < 0 => -i
    }

    println(abs(11))
    println(abs(-11))
  }
}

三、模式匹配类型

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

常量

代码语言:javascript
复制
    // 匹配常量
    def describeConst(s: Any): String = s match {
      case 1 => "number 1"
      case "hello" => "String hello"
      case '+' => "+"
      case 's' => "Char s"
      case _ => ""
    }
    
    println(describeConst(1))
    println(describeConst('s'))
    println(describeConst(11))

类型

代码语言:javascript
复制
	// 匹配类型
	 def deprecateType(x: Any): String = x match {
	      case i: Int => "int" + i
	      case s: String => "String" + s
	      case list: List[String] => "list" + list
	      case array: Array[Int] => "Array[Int]" + array.mkString("-")
	      case a => "Something type"
	    }

    println(deprecateType(23))
    println(deprecateType("12"))
    println(deprecateType(List("mi", "hao")))
    println(deprecateType(List(12, 21)))

数组

对于数组可以定义多种匹配形式,可以定义模糊的元素类型匹配、元素数量匹配或者精确的某个数组元素值匹配

代码语言:javascript
复制
	// 匹配数组
    for (arr <- List(
      Array(0),
      Array(1, 0),
      Array(0, 1, 0),
      Array(1, 1, 0),
      Array(12, 21, 34, 32),
      Array("hello", 34, 32),
    )) {
      val result = arr match {
        case Array(0) => "0"
        case Array(1, 0) => "Array(1,0)"
        case Array(x, y) => "Array:" + x + ", " + y
        case Array(0, _*) => "以0开头的数组"
        case Array(x, 1, y) => "中间为1 的三元数组"
        case _ => "something else"
      }
    }

列表

使用::运算符匹配first :: second :: rest,将一个列表拆成三份,第一个第二个元素和剩余元素构成的列表。

代码语言:javascript
复制
    // 匹配列表 方式一
    for (list <- List(
      List(0),
      List(1, 0),
      List(0, 0, 0),
      List(1, 1, 0),
      List(999)
    )) {
      val result = list match {
        case List(0) => "0"
        case List(x, y) => "list:" + x + ", " + y
        case List(0, _*) => "以0开头的list"
        case List(a) => "list(a)" + a
        case _ => "something else"
      }
    }

    // 方式二
    val list = List(1, 34, 3, 2, 3, 2, 3, 6)
    list match {
      case first :: second :: rest => println(s"first:$first second: $second rest: $rest")
      case _ => "something else"
    }

元组

可以匹配n元组、匹配元素类型、匹配元素值。如果只关心某个元素,其他就可以用通配符或变量。元组大小固定,所以不能用_*

代码语言:javascript
复制
    // 元组类型
    for (tuple <- List(
      (0, 1),
      (0, 1),
      (0, 1, 0),
      (0, 1, 1),
      ("hello", true, 0.5)
    )) {
      val result = tuple match {
        case (a,b) => " "+ a + ", " +b
        case (0,_) => "(0,_)"
        case (a,1,_) => "(a,1,_)" + a
        case (x,y,z) => "(x,y,z)"
        case _ => "something else"
      }
    }

对象及样例类

匹配对象

代码语言:javascript
复制
object Test04_MathObject {
  def main(args: Array[String]): Unit = {
    val student = new Student("alice", 15)

    //针对对象的实例进行匹配
    val result = student match {
      case Student("alice", 15) => "alice, 15"
      case _ => "else"
    }
  }
}

class Student(val name: String, val age: Int)

object Student {
  def apply(name: String, age: Int): Student = new Student(name, age)

  // 实现unapply
  def unapply(student: Student): Option[(String, Int)] = {
    if (student == null){
      None
    } else{
      Some(student.name,student.age)
    }
  }
}
  • 当将 Student("alice", 15))写在 case 后时 case Student("alice", 15) => "alice, 20",会默认调用 unapply 方法(对象提取器),student 作为 unapply 方法的参数,unapply 方法将 student 对象的 nameage 属性提取出来,与 Student("alice", 15)) 中的属性值进行匹配
  • case 中对象的 unapply 方法(提取器)返回 Some,且所有属性均一致,才算匹配成功, 属性不一致,或返回 None,则匹配失败。
  • 若只提取对象的一个属性,则提取器为 unapply(obj:Obj):Option[T]
  • 若提取对象的多个属性,则提取器为 unapply(obj:Obj):Option[(T1,T2,T3…)]
  • 若提取对象的可变个属性,则提取器为 unapplySeq(obj:Obj):Option[Seq[T]]

样例类

代码语言:javascript
复制
case class 类名 (参数1,参数2,......)
  • 样例类仍然是类,和普通类相比,只是其自动生成了伴生对象,并且伴生对象中自动提供了一些常用的方法,如 apply、unapply、toString、equals、hashCodecopy
  • 样例类是为模式匹配而优化的类,因为其默认提供了 unapply 方法,因此,样例类可以直接使用模式匹配,而无需自己实现 unapply 方法。
  • 构造器中的每一个参数都成为 val修饰的变量
代码语言:javascript
复制
object Test_MatchCaseClass {
  def main(args: Array[String]): Unit = {
    val student = Student("alice", 15)

    val result = student1 match {
      case Student("alice", 15) => "alice, 20"
      case _ => "else"
    }
    println(result)
  }
}

case class Student(name: String, age: Int)

四、声明变量中的模式匹配

变量声明也可以是一个模式匹配的过程。

代码语言:javascript
复制
object Test_MathTupleExtend {
  def main(args: Array[String]): Unit = {
    // 1.在变量声明时匹配
    val (x,y) = (10,"hello")
    println(s"$x $y")
    val List(first,second,_*) = List(12,21,21,21,34)
    println(s"$first $second ")

    val fir :: sec :: res =List(12,21,34)
    println(s"$fir $sec $res")
  }
}

五、for表达式模式匹配

  • 元组中取元素时,必须用_1 _2 …,可以用元组赋值将元素赋给变量
  • 指定特定元素的值,可以实现类似于循环守卫的功能
代码语言:javascript
复制
object TestMatchFor {
	 def main(args: Array[String]): Unit = {
		 val map = Map("A" -> 1, "B" -> 0, "C" -> 3)
		 // //直接将 map 中的 k-v 遍历出来
		 for ((k, v) <- map) { 
		 	println(k + " -> " + v) //3 个
		 }

		 //遍历 value=0 的 k-v ,如果 v 不是 0,过滤
		 for ((k, 0) <- map) {
			 println(k + " --> " + 0) // B->0
		 }

		 //if v == 0 是一个过滤的条件
		 for ((k, v) <- map if v >= 1) {
			 println(k + " ---> " + v) // A->1 和 c->33
		 }
	 } 
 }

六、偏函数模式匹配

  • 偏函数也是函数的一种,通过偏函数我们可以方便的对输入参数做更精确的检查。例如该偏函数的输入类型为List[Int],、需要的是第一个元素是 0 的集合,这就是通过模式匹配实现的。

偏函数定义

代码语言:javascript
复制
val second: PartialFunction[List[Int], Option[Int]] = {
 case x :: y :: _ => Some(y)
}
  • second:偏函数名称
  • PartialFunction[List[Int], Option[Int]]: 偏函数类型
  • 该偏函数的功能是返回输入的 List 集合的第二个元素

举个例子:

代码语言:javascript
复制
object Test_PartialFunction {
  def main(args: Array[String]): Unit = {
    val list = List(("a,", 12), ("b", 34), ("c", 45))

    // map转换 key不变 value两倍
    val newList = list.map(tuple => (tuple._1, tuple._2 * 2))

    // 模式匹配 对元素元素赋值
    val newList2 = list.map(
      tuple => {
        tuple match {
          case (word, count) => (word, count * 2)
        }
      }
    )

    // 省略lambda表达式 表示偏函数
    val newList3 = list.map {
      case (word, count) => (word, count * 2)
    }

    // 函数应用 求绝对值
    val positiveAbs: PartialFunction[Int, Int] = {
      case x if x >= 0 => x
    }

    val pnegativeAbs: PartialFunction[Int, Int] = {
      case x if x < 0 => -x
    }

    def abs(x: Int): Int= (positiveAbs orElse pnegativeAbs)(x)

    println(abs(21))
  }
}

本次Scala中的模式匹配部分到这里就结束了,知识点较为简单但是使用起来特别的灵活,希望对大家有所帮助!!!

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-07-28,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 文章目录
  • 一、概述
  • 二、模式守卫
  • 三、模式匹配类型
    • 常量
      • 类型
        • 数组
          • 列表
            • 元组
              • 对象及样例类
              • 四、声明变量中的模式匹配
              • 五、for表达式模式匹配
              • 六、偏函数模式匹配
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档