您现在的位置是:首页 >学无止境 >Scala模式匹配网站首页学无止境

Scala模式匹配

阿瞒有我良计15 2023-05-26 04:00:02
简介Scala模式匹配

Scala中有一个非常强大的模式匹配机制,应用也非常广泛, 例如:

  • 判断固定值

  • 类型查询

  • 快速获取数据

简单模式匹配

一个模式匹配包含了一系列备选项,每个备选项都开始于关键字 case。且每个备选项都包含了一个模式及一到多个表达式。箭头符号 => 隔开了模式和表达式。

格式: 

  变量 match {
      case "常量 1 " => 表达式 1
      case "常量 2 " => 表达式 2
      case "常量 3 " => 表达式 3
      case _ => 表达式 4 // 默认匹配项
  }

执行流程

  1. 先执行第一个case, 看变量值和该case对应的常量值是否一致.

  2. 如果一致, 则执行该case对应的表达式.

  3. 如果不一致, 则往后执行下一个case, 看变量值和该case对应的常量值是否一致.

  4. 以此类推, 如果所有的case都不匹配, 则执行case _对应的表达式.

需求: 

  1. 提示用户录入一个单词并接收.

  2. 判断该单词是否能够匹配以下单词,如果能匹配,返回一句话

  3. 打印结果.

 

代码示例: 

package test11

import scala.io.StdIn

object Test2 {
  def main(args: Array[String]): Unit = {
    println("请输入一个字符串")
    val str = StdIn.readLine()

    val result = str match {
      case "hadoop" => "大数据分布式存储和计算框架"
      case "zookeeper" => "大数据分布式协调服务框架"
      case "spark" => "大数据分布式内存计算框架"
      case _ => "未匹配"
    }

    println(result)

    //简写形式
    val result2 = str match {
      case "hadoop" => println("大数据分布式存储和计算框架")
      case "zookeeper" => println("大数据分布式协调服务框架")
      case "spark" => println("大数据分布式内存计算框架")
      case _ => println("未匹配")
    }
  }

}

匹配类型

除了匹配数据之外, match表达式还可以进行类型匹配。如果我们要根据不同的数据类型,来执行不同的逻辑,也可以使用match表达式来实现。

格式:

对象名 match {
  	case 变量名 1 : 类型 1 => 表达式 1
  	case 变量名 2 : 类型 2 => 表达式 2
  	case 变量名 3 : 类型 3 => 表达式 3
  	...
  	case _ => 表达式 4
}

需求

  1. 定义一个变量为Any类型,然后分别给其赋值为"hadoop"、 1 、1.0

  2. 定义模式匹配,然后分别打印类型的名称

代码示例: 

package test11

object Test3 {
  def main(args: Array[String]): Unit = {
    //    val a: Any = 1.0
    //    val a: Any = "hello"
    val a: Any = 1
    val result = a match {
      case x: String => s"$x 是String类型的数据"
      case x: Double => s"$x 是Double类型的数据"
      case x: Int => s"$x 是Int类型的数据"
      case _ => "未匹配"
    }
    println(result)

    //    4. 优化版, 如果在case校验的时候, 变量没有被使用, 则可以用_替代.
    val result1 = a match {
      case _: String => "String"
      case _: Int => "Int"
      case _: Double => "Double"
      case _ => "未匹配"
    }

    println(result1)
  }
}

守卫

所谓的守卫指的是在case语句中添加if条件判断, 这样可以让我们的代码更简洁, 更优雅.

格式

  变量 match {
  	case 变量名 if条件 1 => 表达式 1
  	case 变量名 if条件 2 => 表达式 2
  	case 变量名 if条件 3 => 表达式 3
  	...
  	case _ => 表达式 4
  }

需求

  1. 从控制台读入一个数字a(使用StdIn.readInt)

  2. 如果 a >= 0 而且 a <= 3,打印[0-3]

  3. 如果 a >= 4 而且 a <= 8,打印[4,8]

  4. 否则,打印未匹配

package test11

import scala.io.StdIn

object Test4 {
  def main(args: Array[String]): Unit = {
    println("请输入一个整数:")
    val num = StdIn.readInt()
    num match {
      case a if a >= 0 && a <= 3 => println("[0 - 3]")
      case a if a >= 4 && a <= 8 => println("[4 - 8]")
      case _ => println("不匹配")
    }
  }
}

 

匹配样例类

Scala中可以使用模式匹配来匹配样例类,从而实现可以快速获取样例类中的成员数据。后续,我们在开发Akka案例时,还会经常用到。

格式

  对象名 match {
	case 样例类型 1 (字段 1 , 字段 2 , 字段n) => 表达式 1
	case 样例类型 2 (字段 1 , 字段 2 , 字段n) => 表达式 2
	case 样例类型 3 (字段 1 , 字段 2 , 字段n) => 表达式 3
  	...
  	case _ => 表达式 4
  }

注意:

  1. 样例类型后的小括号中, 编写的字段个数要和该样例类的字段个数保持一致.

  2. 通过match进行模式匹配的时候, 要匹配的对象必须声明为: Any类型.

需求

  1. 创建两个样例类Customer(包含姓名, 年龄字段), Order(包含id字段)

  2. 分别定义两个样例类的对象,并指定为Any类型

  3. 使用模式匹配这两个对象,并分别打印它们的成员变量值

 代码示例:

package test11

object Test5 {
  case class Customer(var name: String, var age: Int)

  case class Order(id: Int)

  def main(args: Array[String]): Unit = {
    val c: Any = Customer("Tom", 23)
    val o: Any = Order(123)
    val arr: Any = Array(0, 1)
    c match {
      case Customer(a, b) => println(s"Customer类型的对象,name=$a,age=$b")
      case Order(c) => println(s"Order类型,id=$c")
      case _ => println("未匹配")
    }

    o match {
      case Customer(a, b) => println(s"Customer类型的对象,name=$a,age=$b")
      case Order(c) => println(s"Order类型,id=$c")
      case _ => println("未匹配")
    }

    arr match {
      case Customer(a, b) => println(s"Customer类型的对象,name=$a,age=$b")
      case Order(c) => println(s"Order类型,id=$c")
      case _ => println("未匹配")
    }
  }
}

匹配集合

除了上述功能之外, Scala中的模式匹配,还能用来匹配数组, 元组, 集合(列表, 集, 映射)等。

匹配数组

package test11

object Test6 {
  def main(args: Array[String]): Unit = {
    val arr1 = Array(1, 2, 3)
    val arr2 = Array(0)
    val arr3 = Array(1, 2, 4, 5, 6, 7)

    arr1 match {
      case Array(1, x, y) => println(s"匹配长度为 3 , 首元素为 1 , 后两个元素是: $x, $y")
      case Array(0) => println("匹配只有一个0元素的数组")
      case Array(1, _*) => println("匹配:第一个元素是1,后边的元素随意")
      case _ => println("未匹配")
    }

    arr2 match {
      case Array(1, x, y) => println(s"匹配长度为 3 , 首元素为 1 , 后两个元素是: $x, $y")
      case Array(0) => println("匹配只有一个0元素的数组")
      case Array(1, _*) => println("匹配:第一个元素是1,后边的元素随意")
      case _ => println("未匹配")
    }

    arr3 match {
      case Array(1, x, y) => println(s"匹配长度为 3 , 首元素为 1 , 后两个元素是: $x, $y")
      case Array(0) => println("匹配只有一个0元素的数组")
      case Array(1, _*) => println("匹配:第一个元素是1,后边的元素随意")
      case _ => println("未匹配")
    }
  }
}

匹配列表

package test11

object Test7 {
  def main(args: Array[String]): Unit = {
    val list1 = List(0)
    val list2 = List(0, 1, 2, 3, 4, 5)
    val list3 = List(1, 2)

    list1 match {
      case List(0) => println("匹配: 只有一个0元素的列表")
      case List(0, _*) => println("匹配: 0开头,后边元素无所谓的列表")
      case List(x, y) => println(s"匹配:只有俩个元素的列表,元素为:$x,$y")
      case _ => println("未匹配")
    }

    //思路二: 采用关键字优化 Nil, tail
    list1 match {
      case 0 :: Nil => println("匹配: 只有一个 0 元素的列表")
      case 0 :: tail => println("匹配: 0 开头, 后边元素无所谓的列表")
      case x :: y :: Nil => println(s"匹配: 只有两个元素的列表, 元素为: $x, $y")
      case _ => println("未匹配")
    }

    list2 match {
      case List(0) => println("匹配: 只有一个0元素的列表")
      case List(0, _*) => println("匹配: 0开头,后边元素无所谓的列表")
      case List(x, y) => println(s"匹配:只有俩个元素的列表,元素为:$x,$y")
      case _ => println("未匹配")
    }

    list3 match {
      case List(0) => println("匹配: 只有一个0元素的列表")
      case List(0, _*) => println("匹配: 0开头,后边元素无所谓的列表")
      case List(x, y) => println(s"匹配:只有俩个元素的列表,元素为:$x,$y")
      case _ => println("未匹配")
    }
  }
}

匹配元组

package test11

object Test8 {
  def main(args: Array[String]): Unit = {
    val a = (1, 2, 3)
    val b = (3, 4, 5)
    val c = (3, 4)

    a match {
      case (1, x, y) => println(s"匹配:长度为3,以1开头,后面俩个元素随意的元组,这里的后俩个元素是:$x,$y")
      case (x, y, 5) => println(s"匹配:长度为3,以5结尾,前边俩个元素随意的元组,这里的前俩个元素是:$x,$y")
      case _ => println("未匹配")
    }
  }
}

变量声明中的模式匹配

在定义变量时,可以使用模式匹配快速获取数据. 例如: 快速从数组,列表中获取数据.

package test11

object Test9 {
  def main(args: Array[String]): Unit = {
    val arr = (0 to 10).toArray
    //使用模式匹配分别获取第二个、第三个、第四个元素
    val Array(_, x, y, z, _*) = arr
    println(x, y, z)


    val list = (0 to 10).toList
    //    使用模式匹配分别获取第一个、第二个元素
    val List(a, b, _*) = list
    //    使用模式匹配分别获取第一个、第二个元素
    val c :: d :: tail = list

    println(a, b)
    println(c, d)
  }

}

匹配for表达式

Scala中还可以使用模式匹配来匹配for表达式,从而实现快速获取指定数据, 让我们的代码看起来更简洁, 更优雅.

需求

  1. 定义变量记录学生的姓名和年龄, 例如: "张三" -> 23, "李四" -> 24, "王五" -> 23, "赵六" -> 26

  2. 获取所有年龄为 23 的学生信息, 并打印结果.

package test11

object Test10 {
  def main(args: Array[String]): Unit = {
    val map1 = Map("张三" -> 23, "李四" -> 24, "王五" -> 23, "赵六" -> 26)
    for ((k, v) <- map1 if v == 23) println(s"$k = $v")

    println("-" * 15)

    for ((k, 23) <- map1) println(k + " = 23")
  }
}

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。