文本文档做网站,wordpress导购淘宝客主题,广东省建设厅网站首页,南充网站建设公司模式匹配第 8 章 模式匹配8.1 基本语法8.2 模式守卫8.3 模式匹配类型8.3.1 匹配常量8.3.2 匹配类型8.3.3 匹配数组8.3.4 匹配列表8.3.5 匹配元组8.3.6 匹配对象及样例类8.4 变量声明中的模式匹配8.5 for 表达式中的模式匹配8.6 偏函数中的模式匹配(了解)第 8 章 模式匹配
Scal…
模式匹配第 8 章 模式匹配8.1 基本语法8.2 模式守卫8.3 模式匹配类型8.3.1 匹配常量8.3.2 匹配类型8.3.3 匹配数组8.3.4 匹配列表8.3.5 匹配元组8.3.6 匹配对象及样例类8.4 变量声明中的模式匹配8.5 for 表达式中的模式匹配8.6 偏函数中的模式匹配(了解)第 8 章 模式匹配
Scala 中的模式匹配类似于 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 从语法中补充了更多的功能所以更加强大。 8.1 基本语法 模式匹配语法中采用 match 关键字声明每个分支采用 case 关键字进行声明当需 要匹配时会从第一个 case 分支开始如果匹配成功那么执行对应的逻辑代码如果匹 配不成功继续执行下一个分支进行判断。如果所有 case 都不匹配那么会执行 case _分支 类似于 Java 中 default 语句 object TestMatchCase {def main(args: Array[String]): Unit {var a: Int 10var b: Int 20var operator: Char dvar result operator match {case a bcase - a - bcase * a * bcase / a / bcase _ illegal}println(result)}
}1说明
1如果所有 case 都不匹配那么会执行 case _ 分支类似于 Java 中 default 语句 若此时没有 case _ 分支那么会抛出 MatchError。2每个 case 中不需要使用 break 语句自动中断 case。3match case 语句可以匹配任何类型而不只是字面量。4 后面的代码块直到下一个 case 语句之前的代码是作为一个整体执行可以 使用{}括起来也可以不括。
8.2 模式守卫
1说明 如果想要表达匹配某个范围的数据就需要在模式匹配中增加条件守卫。 2案例实操
object TestMatchGuard {def main(args: Array[String]): Unit {def abs(x: Int) x match {case i: Int if i 0 icase j: Int if j 0 -jcase _ type illegal}println(abs(-5))}
}8.3 模式匹配类型
8.3.1 匹配常量
1说明 Scala 中模式匹配可以匹配所有的字面量包括字符串字符数字布尔值等等。 2实操
object TestMatchVal {def main(args: Array[String]): Unit {println(describe(6))}def describe(x: Any) x match {case 5 Int fivecase hello String hellocase true Boolean truecase Char }
}8.3.2 匹配类型
1说明 需要进行类型判断时可以使用前文所学的 isInstanceOf[T]和 asInstanceOf[T]也可使 用模式匹配实现同样的功能。 2案例实操 object TestMatchClass {def describe(x: Any) x match {case i: Int Intcase s: String String hellocase m: List[_] Listcase c: Array[Int] Array[Int]case someThing something else someThing}def main(args: Array[String]): Unit {//泛型擦除println(describe(List(1, 2, 3, 4, 5)))//数组例外可保留泛型println(describe(Array(1, 2, 3, 4, 5, 6)))println(describe(Array(abc)))}
}8.3.3 匹配数组
1说明 scala 模式匹配可以对集合进行精确的匹配例如匹配只有两个元素的、且第一个元素 为 0 的数组。 2案例实操
object TestMatchArray {def main(args: Array[String]): Unit {for (arr - Array(Array(0), Array(1, 0), Array(0, 1, 0),
Array(1, 1, 0), Array(1, 1, 0, 1), Array(hello, 90))) { // 对
一个数组集合进行遍历val result arr match {case Array(0) 0 //匹配 Array(0) 这个数组case Array(x, y) x , y //匹配有两个元素的数
组然后将将元素值赋给对应的 x,ycase Array(0, _*) 以 0 开头的数组 //匹配以 0 开头和
数组case _ something else}println(result result)}}
}8.3.4 匹配列表
1方式一
object TestMatchList {def main(args: Array[String]): Unit {//list 是一个存放 List 集合的数组//请思考如果要匹配 List(88) 这样的只含有一个元素的列表,并原值返
回.应该怎么写for (list - Array(List(0), List(1, 0), List(0, 0, 0), List(1,
0, 0), List(88))) {val result list match {case List(0) 0 //匹配 List(0)case List(x, y) x , y //匹配有两个元素的 Listcase List(0, _*) 0 ...case _ something else}println(result)}}
}2方式二
object TestMatchList {def main(args: Array[String]): Unit {val list: List[Int] List(1, 2, 5, 6, 7)list match {case first :: second :: rest println(first -
second - rest)case _ println(something else)}}
}8.3.5 匹配元组
object TestMatchTuple {def main(args: Array[String]): Unit {//对一个元组集合进行遍历for (tuple - Array((0, 1), (1, 0), (1, 1), (1, 0, 2))) {val result tuple match {case (0, _) 0 ... //是第一个元素是 0 的元组case (y, 0) y 0 // 匹配后一个元素是 0 的对
偶元组case (a, b) a bcase _ something else //默认}println(result)}}
}扩展案例
object TestGeneric {def main(args: Array[String]): Unit {//特殊的模式匹配 1 打印元组第一个元素for (elem - Array((a, 1), (b, 2), (c, 3))) {println(elem._1)}for ((word,count) - Array((a, 1), (b, 2), (c, 3))) {println(word)}for ((word,_) - Array((a, 1), (b, 2), (c, 3))) {println(word)}for ((a,count) - Array((a, 1), (b, 2), (c, 3))) {println(count)}println(--------------)//特殊的模式匹配 2 给元组元素命名var (id,name,age): (Int, String, Int) (100, zs, 20)println((id,name,age))println(--------------)//特殊的模式匹配 3 遍历集合中的元组给 count * 2var list: List[(String, Int)] List((a, 1), (b, 2), (c, 3))//println(list.map(t (t._1, t._2 * 2)))println(list.map{case (word,count)(word,count*2)})var list1 List((a, (a, 1)), (b, (b, 2)), (c, (c, 3)))println(list1.map{case (groupkey,(word,count))(word,count*2)})}
}8.3.6 匹配对象及样例类
1基本语法
class User(val name: String, val age: Int)
object User{def apply(name: String, age: Int): User new User(name, age)def unapply(user: User): Option[(String, Int)] {if (user null)NoneelseSome(user.name, user.age)}
}
object TestMatchUnapply {def main(args: Array[String]): Unit {val user: User User(zhangsan, 11)val result user match {case User(zhangsan, 11) yescase _ no}println(result)}
}小结 ➢ val user User(“zhangsan”,11)该语句在执行时实际调用的是 User 伴生对象中的 apply 方法因此不用 new 关键字就能构造出相应的对象。 ➢ 当将 User(“zhangsan”, 11)写在 case 后时[case User(“zhangsan”, 11) “yes”]会默 认调用 unapply 方法(对象提取器)user 作为 unapply 方法的参数unapply 方法 将 user 对象的 name 和 age 属性提取出来与 User(“zhangsan”, 11)中的属性值进行 匹配 ➢ case 中对象的 unapply 方法(提取器)返回 Some且所有属性均一致才算匹配成功, 属性不一致或返回 None则匹配失败。 ➢ 若只提取对象的一个属性则提取器为 unapply(obj:Obj):Option[T] 若提取对象的多个属性则提取器为 unapply(obj:Obj):Option[(T1,T2,T3…)] 若提取对象的可变个属性则提取器为 unapplySeq(obj:Obj):Option[Seq[T]] 2样例类
1语法 case class Person (name: String, age: Int)
2说明
○1 样例类仍然是类和普通类相比只是其自动生成了伴生对象并且伴生对象中 自动提供了一些常用的方法如 apply、unapply、toString、equals、hashCode 和 copy。○2 样例类是为模式匹配而优化的类因为其默认提供了 unapply 方法因此样例 类可以直接使用模式匹配而无需自己实现 unapply 方法。○3 构造器中的每一个参数都成为 val除非它被显式地声明为 var不建议这样做
3实操
上述匹配对象的案例使用样例类会节省大量代码
case class User(name: String, age: Int)
object TestMatchUnapply {def main(args: Array[String]): Unit {val user: User User(zhangsan, 11)val result user match {case User(zhangsan, 11) yescase _ no}println(result)}
}8.4 变量声明中的模式匹配
case class Person(name: String, age: Int)
object TestMatchVariable {def main(args: Array[String]): Unit {val (x, y) (1, 2)println(sx$x,y$y)val Array(first, second, _*) Array(1, 7, 2, 9)println(sfirst$first,second$second)val Person(name, age) Person1(zhangsan, 16)println(sname$name,age$age)}
}8.5 for 表达式中的模式匹配
object TestMatchFor {def main(args: Array[String]): Unit {val map Map(A - 1, B - 0, C - 3)for ((k, v) - map) { //直接将 map 中的 k-v 遍历出来println(k - v) //3 个}println(----------------------)//遍历 value0 的 k-v ,如果 v 不是 0,过滤for ((k, 0) - map) {println(k -- 0) // B-0}println(----------------------)//if v 0 是一个过滤的条件for ((k, v) - map if v 1) {println(k --- v) // A-1 和 c-33}}
}8.6 偏函数中的模式匹配(了解) 偏函数也是函数的一种通过偏函数我们可以方便的对输入参数做更精确的检查。例如 该偏函数的输入类型为 List[Int]而我们需要的是第一个元素是 0 的集合这就是通过模式 匹配实现的。 1 偏函数定义
val second: PartialFunction[List[Int], Option[Int]] {case x :: y :: _ Some(y)
}注该偏函数的功能是返回输入的 List 集合的第二个元素 2偏函数原理 上述代码会被 scala 编译器翻译成以下代码与普通函数相比只是多了一个用于参数 检查的函数——isDefinedAt其返回值类型为 Boolean。 val second new PartialFunction[List[Int], Option[Int]] {//检查输入参数是否合格override def isDefinedAt(list: List[Int]): Boolean list match
{case x :: y :: _ truecase _ false}//执行函数逻辑override def apply(list: List[Int]): Option[Int] list match
{case x :: y :: _ Some(y)}
}3偏函数使用 偏函数不能像 second(List(1,2,3))这样直接使用因为这样会直接调用 apply 方法而应 该调用 applyOrElse 方法如下 second.applyOrElse(List(1,2,3), (_: List[Int]) None)applyOrElse 方法的逻辑为 if (ifDefinedAt(list)) apply(list) else default。如果输入参数满 足条件即 isDefinedAt 返回 true则执行 apply 方法否则执行 defalut 方法default 方法 为参数不满足要求的处理逻辑。
4 案例实操
1需求 将该 List(1,2,3,4,5,6,“test”)中的 Int 类型的元素加一并去掉字符串。
def main(args: Array[String]): Unit {val list List(1,2,3,4,5,6,test)val list1 list.map {a a match {case i: Int i 1case s: String s 1}}println(list1.filter(aa.isInstanceOf[Int]))
}2实操
方法一 List(1,2,3,4,5,6,“test”).filter(.isInstanceOf[Int]).map(.asInstanceOf[Int] - 1).foreach(println)方法二 List(1, 2, 3, 4, 5, 6, “test”).collect { case x: Int x 1 }.foreach(println)