一、模式匹配是什么?
核心思想:模式匹配就像"分类整理物品"------你提前设定好不同类别的规则,遇到一个物品时,自动将它归到对应的类别,并触发相应的操作。
和 if-else
的区别:
if-else
是逐个条件判断(需要手动写条件)- 模式匹配是结构化拆解(自动按形状匹配)
二、模式匹配的 8 大应用场景
场景 1:匹配数据类型(判断变量类型)
scala复制代码
val obj: Any = "Hello"
obj match {
case s: String => println(s"这是字符串:$s")
case i: Int => println(s"这是整数:$i")
case _ => println("其他类型")
}
解释:
- 如果
obj
是String
,打印字符串; - 如果是
Int
,打印整数; _
表示默认情况(类似else
)。
场景 2:匹配常量值(类似 switch
)
scala复制代码
val day = "Monday"
day match {
case "Monday" => println("周一")
case "Tuesday" => println("周二")
case _ => println("其他天")
}
对比 if-else
:
scala复制代码
if (day == "Monday") println("周一")
else if (day == "Tuesday") println("周二")
else println("其他天")
优势:代码更简洁、结构化。
场景 3:匹配元组(结构化数据)
scala复制代码
val tuple = (1, "apple")
tuple match {
case (1, fruit) => println(s"数量为 1,水果是 $fruit")
case (qty, "banana") => println(s"香蕉有 $qty 个")
case _ => println("未知")
}
输出 :数量为 1,水果是 apple
关键点 :自动按结构拆解元组,并绑定变量(如 fruit
)。
场景 4:匹配列表(拆解元素)
scala复制代码
val list = List(1, 2, 3)
list match {
case Nil => println("空列表")
case head :: tail => println(s"第一个元素是 $head,剩余部分是 $tail")
}
输出 :第一个元素是 1,剩余部分是 List(2, 3)
说明:
::
是列表的构造操作符(head
是第一个元素,tail
是剩余部分)。- 可以匹配不同长度的列表(如
case List(a, b)
匹配长度为 2 的列表)。
场景 5:匹配类对象(case class
)
scala复制代码
// 定义 case class(自动支持模式匹配)
case class Student(name: String, age: Int)
val student = Student("张三", 18)
student match {
case Student("张三", age) => println(s"找到张三,年龄 $age")
case Student(name, 20) => println(s"找到年龄 20 的学生:$name")
case _ => println("其他学生")
}
输出 :找到张三,年龄 18
关键 :case class
天生适合模式匹配(自动提供解构能力)。
场景 6:匹配守卫条件(if
增强)
scala复制代码
val num = 15
num match {
case n if n < 10 => println("小于 10")
case n if n % 2 == 0 => println("偶数")
case _ => println("其他")
}
输出 :其他
作用:在匹配模式后增加条件过滤。
场景 7:处理 Option
类型(安全处理空值)
scala复制代码
val maybeName: Option[String] = Some("Alice")
maybeName match {
case Some(name) => println(s"名字是 $name")
case None => println("没有名字")
}
对比 Java 的 null
检查:
java复制代码
if (maybeName != null) {
System.out.println("名字是 " + maybeName);
} else {
System.out.println("没有名字");
}
优势:更安全、避免空指针异常。
场景 8:异常处理(try-catch
)
scala复制代码
try {
// 可能抛出异常的代码
} catch {
case e: FileNotFoundException => println("文件没找到")
case e: IOException => println("IO 错误")
case _: Exception => println("其他异常")
}
说明:Scala 的异常处理底层也是模式匹配!
三、模式匹配的底层原理
- 编译阶段 :Scala 编译器会将模式匹配转换为高效的
if-else
或switch
字节码。 - 优化 :对于
case class
或密封类(sealed class
),编译器会检查是否覆盖所有可能情况。
四、模式匹配的 3 大优势
- 代码简洁:用结构代替繁琐的条件判断。
- 安全性 :
- 编译时检查是否覆盖所有情况(对
sealed class
)。 - 避免直接访问对象内部字段(通过解构)。
- 编译时检查是否覆盖所有情况(对
- 表达力强:能处理复杂的数据结构(如嵌套的 JSON、XML)。
五、最佳实践
-
优先用
case class
:为需要模式匹配的类添加case
修饰符。 -
密封类(
sealed
) :如果类的所有子类已知,用sealed
修饰父类,编译器会检查匹配是否完整。scala复制代码
sealed trait Message case class Text(content: String) extends Message case class Image(url: String) extends Message def process(msg: Message) = msg match { case Text(content) => println(s"文字消息:$content") case Image(url) => println(s"图片地址:$url") // 不需要默认分支,因为密封类已覆盖所有情况 }
-
避免过度使用 :简单判断用
if-else
更直观。
六、练习题(自测理解)
-
以下代码输出什么?
scala复制代码
val x = List(1, 2, 3) x match { case List(1, _*) => println("以 1 开头") case _ => println("其他") }
答案输出:以 1 开头(`_*` 匹配剩余任意元素)
-
如何用模式匹配判断一个
List
是否为空或只有一个元素?答案```scala list match { case Nil => println("空列表") case head :: Nil => println("只有一个元素") case _ => println("多个元素") } ```