Scala的模式匹配

Scala的模式匹配

Scala 中的模式匹配类似于Java 中的 switch 语法:下面是java中switch代码:

int i = 10
switch (i) {
 case 10 :
   System.out.println("10");
   break;
case 20 :
   System.out.println("20");
   break;
default :
  System.out.println("other number");
  break;
}

但是 scala 从语法中补充了更多的功能,所以更加强大。

基本语法

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

object Test_PatternMatchBase {
  def main(args: Array[String]): Unit = {
    // 1. 基本定义语法
    val x: Int = 5
    val y: String = x match {
      case 1 => "one"
      case 2 => "two"
      case 3 => "three"
      case _ => "other"
    }
    println(y)

    // 2. 示例:用模式匹配实现简单二元运算
    val a = 25
    val b = 13

    def matchDualOp(op: Char): Int = op match {
      case '+' => a + b
      case '-' => a - b
      case '*' => a * b
      case '/' => a / b
      case '%' => a % b
      case _ => -1
    }

    println(matchDualOp('+'))
    println(matchDualOp('/'))
    println(matchDualOp('\\'))

    println("=========================")

    // 3. 模式守卫
    // 求一个整数的绝对值
    def abs(num: Int): Int = {
      num match {
        case i if i >= 0 => i
        case i if i < 0 => -i
      }
    }

    println(abs(67))
    println(abs(0))
    println(abs(-24))
  }
}
  • 说明
    (1) 如果所有 case 都不匹配,那么会执行 case _ 分支,类似于 Java 中 default 语句,若此时没有case _ 分支,那么会抛出MatchError。
    (2) 每个case 中,不需要使用break 语句,自动中断case。
    (3) match case 语句可以匹配任何类型,而不只是字面量。
    (4) => 后面的代码块,直到下一个 case 语句之前的代码是作为一个整体执行,可以使用{}括起来,也可以不括。
    在 Scala 中,模式匹配(Pattern matching)是一种强大的特性,用于对数据进行分析和处理。它可以在一个表达式中确定一个值是否匹配了某个模式,并且在匹配成功时执行相应的代码块。模式匹配可以应用于各种类型的对象,包括整数、字符、字符串、列表等。

模式匹配基本使用示例

Scala 的模式匹配语法类似于 switch 语句,但更加强大和灵活。以下是一些基本的模式匹配示例:

val x: Any = 123

x match {
  case i: Int => println("整数:" + i)
  case s: String => println("字符串:" + s)
  case d: Double => println("双精度浮点数:" + d)
  case _ => println("未知类型")
}

在上面的代码中,我们将一个任意类型的值 x 进行了模式匹配。首先,我们使用 case i: Int => 匹配整数类型并将其赋值给变量 i,然后执行 println("整数:" + i) 输出整数。接着,我们使用 case s: String => 匹配字符串类型,并输出对应的信息。最后,我们使用 _ 表示其他所有类型并输出 “未知类型”。

除了基本类型之外,模式匹配还支持对列表、元组等复杂类型进行匹配,例如:

def sum(lst: List[Int]) : Int = lst match {
  case Nil => 0
  case x :: tail => x + sum(tail)
}

println(sum(List(1, 2, 3))) // 输出 6

在上面的代码中,我们定义了一个 sum 函数用于计算列表中所有整数的和。在函数内部,我们使用模式匹配来处理两种情况:当列表为空时(case Nil => 0),返回 0;否则,我们使用 case x :: tail => 匹配列表的头部元素 x 和剩余元素 tail,并递归地调用 sum(tail) 来计算剩余元素的和,并将其与头部元素 x 相加。

需要注意的是,在模式匹配中,每个匹配分支都必须满足类型一致性和互斥性,以避免出现匹配二义性的情况。

模式守卫

  1. 说明
    如果想要表达匹配某个范围的数据,就需要在模式匹配中增加条件守卫。
  2. 代码示例
object TestMatchGuard {
def main(args: Array[String]): Unit = {
 //求一个整数的绝对值
def abs(x: Int) = x match {
case i: Int if i >= 0 => i
case j: Int if j < 0 => -j
case _ => "type illegal"
}
println(abs(-5))
}
}

模式匹配类型

在 Scala 中,模式匹配非常灵活,可以在各种情况下使用。以下是一些常见的模式匹配运用情况示例:

匹配基本类型和常量值

val x: Any = 123

x match {
  case 0 => println("匹配到 0")
  case 1 | 2 => println("匹配到 1 或 2")
  case i: Int if i > 100 => println("匹配到大于 100 的整数")
  case _ => println("未匹配到")
}

匹配元组

val tuple: (String, Int) = ("Scala", 3)

tuple match {
  case ("Java", _) => println("第一个元素是 Java")
  case (str, num) if num > 0 => println(s"第一个元素是 $str,第二个元素是正整数")
  case _ => println("未匹配到")
}

匹配列表List

val list: List[Int] = List(1, 2, 3)

list match {
  case Nil => println("空列表")
  case head :: tail => println(s"头部元素是 $head,剩余元素是 $tail")
}

匹配类和对象

sealed trait Shape
case class Circle(radius: Double) extends Shape
case class Rectangle(width: Double, height: Double) extends Shape
case object UnknownShape extends Shape

val shape: Shape = Circle(3.0)

shape match {
  case Circle(r) => println(s"圆形,半径是 $r")
  case Rectangle(w, h) => println(s"矩形,宽度是 $w,高度是 $h")
  case UnknownShape => println("未知形状")
}

使用模式守卫进行更复杂的匹配

val x: Any = List(1, 2, 3)

x match {
  case list: List[_] if list.nonEmpty => println("非空列表")
  case list: List[_] if list.isEmpty => println("空列表")
  case str: String if str.length > 10 => println("字符串长度大于 10")
  case _ => println("未匹配到")
}

匹配数组

在 Scala 中,匹配数组与匹配列表的方式类似。你可以使用模式匹配对数组进行处理。以下是一个示例:

val array: Array[Int] = Array(1, 2, 3)

array match {
  case Array() => println("空数组")
  case Array(1) => println("单个元素数组")
  case Array(1, 2, _*) => println("以1和2开头的数组")
  case Array(_, _, 3) => println("以3结尾的数组")
  case _ => println("未匹配到")
}

在上面的代码中,我们匹配了不同类型的数组情况。首先,使用 case Array() 匹配空数组;然后,使用 case Array(1) 匹配只包含一个元素的数组;接着,使用 case Array(1, 2, _*) 匹配以 1 和 2 开头的任意长度的数组;最后,使用 case Array(_, _, 3) 匹配以 3 结尾的数组。如果没有匹配到任何情况,就会执行最后一个 case 分支。

需要注意的是,在匹配可变长度的数组时,我们使用了 _* 表示任意长度的数组片段。

变量声明中的模式匹配

在 Scala 中,可以在变量声明中使用模式匹配来提取和赋值变量的值。这种方式被称为模式匹配的变量声明或解构赋值。以下是一个示例:

val tuple: (String, Int) = ("Scala", 3)

val (str, num) = tuple

println(s"字符串:$str")
println(s"整数:$num")

在上面的代码中,我们声明了一个元组 tuple,包含两个元素:一个字符串和一个整数。然后,我们使用模式匹配的方式将元组中的值解构并赋给了两个新的变量 strnum。这样,我们就可以通过这两个变量来访问元组中的值。

除了元组,还可以在变量声明中匹配其他数据结构,比如列表、数组等。示例如下:

val list: List[String] = List("Hello", "World")

val head :: tail = list

println(s"头部元素:$head")
println(s"剩余元素:$tail")

在上面的代码中,我们声明了一个列表 list,包含两个字符串元素。然后,使用模式匹配的变量声明方式将列表的头部元素赋给变量 head,剩余元素赋给变量 tail。这样,我们就可以分别访问列表的头部元素和剩余元素。

需要注意的是,模式匹配的变量声明在匹配失败时会抛出 MatchError 异常。为了避免这种情况,请确保变量声明与待解构的数据结构具有相同的结构和类型。

匹配对象及样例类

在 Scala 中,可以使用模式匹配来匹配各种类型的对象,包括普通类和样例类。其中,样例类是一种特殊的类,它专门用于模式匹配,因为编译器会自动生成带有模式匹配相关方法的代码。以下是一个示例:

sealed trait Fruit
case class Apple(color: String) extends Fruit
case class Banana(length: Int) extends Fruit
case object UnknownFruit extends Fruit

val fruit: Fruit = Apple("red")

fruit match {
  case Apple("red") => println("红色苹果")
  case Banana(len) if len > 10 => println("长度大于 10 的香蕉")
  case UnknownFruit => println("未知水果")
  case _ => println("其他水果")
}

在上面的代码中,我们定义了一个 Fruit 样例类及两个子类 AppleBanana,还有一个对象 UnknownFruit。然后,我们创建了一个 Apple 对象并将其赋给 fruit 变量。接着,使用 match 关键字来匹配不同类型的 Fruit 对象,分别输出相应的提示信息。

需要注意的是,当匹配样例类时,可以使用模式匹配提取出样例类中的属性值,并对其进行比较。在上面的代码中,使用 case Apple("red") 匹配颜色为红色的苹果。

嵌套模式匹配

当数据结构较为复杂时,可以使用嵌套的模式匹配来逐级解构和匹配。

sealed trait Location
case class City(name: String) extends Location
case class Country(name: String, capital: City) extends Location

def printCapital(location: Location): Unit = {
  location match {
    case Country(_, City(capital)) => println(s"首都是$capital")
    case _ => println("未知位置")
  }
}

在上面的代码中,我们定义了一个 Location 类及其两个子类 City 和 Country。Country 类包含一个 City 类的实例作为首都。通过嵌套的模式匹配,我们可以提取和打印出国家的首都。

你可能感兴趣的:(#,Scala,大数据,scala,开发语言)