您现在的位置是:首页 >学无止境 >Scala模式匹配网站首页学无止境
Scala模式匹配
Scala中有一个非常强大的模式匹配机制,应用也非常广泛, 例如:
-
判断固定值
-
类型查询
-
快速获取数据
简单模式匹配
一个模式匹配包含了一系列备选项,每个备选项都开始于关键字 case。且每个备选项都包含了一个模式及一到多个表达式。箭头符号 => 隔开了模式和表达式。
格式:
变量 match {
case "常量 1 " => 表达式 1
case "常量 2 " => 表达式 2
case "常量 3 " => 表达式 3
case _ => 表达式 4 // 默认匹配项
}
执行流程
-
先执行第一个case, 看变量值和该case对应的常量值是否一致.
-
如果一致, 则执行该case对应的表达式.
-
如果不一致, 则往后执行下一个case, 看变量值和该case对应的常量值是否一致.
-
以此类推, 如果所有的case都不匹配, 则执行case _对应的表达式.
需求:
-
提示用户录入一个单词并接收.
-
判断该单词是否能够匹配以下单词,如果能匹配,返回一句话
-
打印结果.
代码示例:
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
}
需求
-
定义一个变量为Any类型,然后分别给其赋值为"hadoop"、 1 、1.0
-
定义模式匹配,然后分别打印类型的名称
代码示例:
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
}
需求
-
从控制台读入一个数字a(使用StdIn.readInt)
-
如果 a >= 0 而且 a <= 3,打印[0-3]
-
如果 a >= 4 而且 a <= 8,打印[4,8]
-
否则,打印未匹配
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
}
注意:
-
样例类型后的小括号中, 编写的字段个数要和该样例类的字段个数保持一致.
-
通过match进行模式匹配的时候, 要匹配的对象必须声明为: Any类型.
需求
-
创建两个样例类Customer(包含姓名, 年龄字段), Order(包含id字段)
-
分别定义两个样例类的对象,并指定为Any类型
-
使用模式匹配这两个对象,并分别打印它们的成员变量值
代码示例:
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表达式,从而实现快速获取指定数据, 让我们的代码看起来更简洁, 更优雅.
需求
-
定义变量记录学生的姓名和年龄, 例如: "张三" -> 23, "李四" -> 24, "王五" -> 23, "赵六" -> 26
-
获取所有年龄为 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")
}
}