本次主要分享Scala中关于模式匹配的内容,Scala中的模式匹配类似于Java中的switch
语法,但是Scala在基于Java的思想上补充了特有的功能。
一、概述
基本语法
value match {
case caseVal1 => returnVal1
case caseVal2 => returnVal2
...
case _ => defaultVal
}
模式匹配语法中,采用 match
关键字声明,每个分支采用 case
关键字进行声明,当需
要匹配时,会从第一个 case
分支开始,如果匹配成功,那么执行对应的逻辑代码,如果匹
配不成功,继续执行下一个分支进行判断。如果所有 case
都不匹配,那么会执行 case _
分支,类似于 Java 中 default 语句。
举个例子:
val x: Int = 2
val y: String = x match {
case 1 => "one"
case 2 => "two"
case 3 => "three"
case _ => "other"
}
第二个例子:
// 示例:使用模式匹配实现简单的二元运算
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推倒式中的循环守卫。
举个例子:
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 中,模式匹配可以匹配所有的字面量,包括字符串,字符,数字,布尔值等等。
常量
// 匹配常量
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))
类型
// 匹配类型
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)))
数组
对于数组可以定义多种匹配形式,可以定义模糊的元素类型匹配、元素数量匹配或者精确的某个数组元素值匹配
// 匹配数组
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
,将一个列表拆成三份,第一个第二个元素和剩余元素构成的列表。
// 匹配列表 方式一
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
元组、匹配元素类型、匹配元素值。如果只关心某个元素,其他就可以用通配符或变量。元组大小固定,所以不能用_*
。
// 元组类型
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"
}
}
对象及样例类
匹配对象
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
对象的name
和age
属性提取出来,与
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]]
样例类
case class 类名 (参数1,参数2,......)
- 样例类仍然是类,和普通类相比,只是其自动生成了伴生对象,并且伴生对象中自动提供了一些常用的方法,如
apply、unapply、toString、equals、hashCode
和copy
。 - 样例类是为模式匹配而优化的类,因为其默认提供了
unapply
方法,因此,样例类可以直接使用模式匹配,而无需自己实现unapply
方法。 - 构造器中的每一个参数都成为
val
修饰的变量
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)
四、声明变量中的模式匹配
变量声明也可以是一个模式匹配的过程。
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 …,可以用元组赋值将元素赋给变量
- 指定特定元素的值,可以实现类似于循环守卫的功能
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 的集合,这就是通过模式匹配实现的。
偏函数定义
val second: PartialFunction[List[Int], Option[Int]] = {
case x :: y :: _ => Some(y)
}
second
:偏函数名称PartialFunction[List[Int], Option[Int]]
: 偏函数类型- 该偏函数的功能是返回输入的 List 集合的第二个元素
举个例子:
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中的模式匹配部分到这里就结束了,知识点较为简单但是使用起来特别的灵活,希望对大家有所帮助!!!