目录
1.scala模式匹配形式
这是java的switch语法
scala的模式匹配(现阶段的java中也支持=>的写法了)写法:
2.基本语法
模式匹配注意点情况说明:
3.模式守卫
4.匹配类型:
5.匹配数组:
6.匹配列表
7.匹配元组
8.匹配对象以及样例类
样例类:
9.变量声明中的模式匹配
10.for表达式中的模式匹配
11.偏函数中的模式匹配
scala的模式匹配类似于java中的switch语法
模式匹配语法中,采用 match 关键字声明,每个分支采用 case 关键字进行声明,当需 要匹配时,会从第一个 case 分支开始,如果匹配成功,那么执行对应的逻辑代码,如果匹 配不成功,继续执行下一个分支进行判断。如果所有 case 都不匹配,那么会执行 case _分支, 类似于 Java 中 default 语句。
(1)如果所有 case 都不匹配,那么会执行 case _ 分支,类似于 Java 中 default 语句, 若此时没有 case _ 分支,那么会抛出 MatchError。
(2)每个 case 中,不需要使用 break 语句,自动中断 case。
(3)match case 语句可以匹配任何类型,而不只是字面量。
(4)=> 后面的代码块,直到下一个 case 语句之前的代码是作为一个整体执行,可以 使用{}括起来,也可以不括。
(5)每一个case条件成立才返回,否则继续往下走
(6) 模式匹配支持类型:所有类型字面量,包括字符串、字符、数字、布尔值、甚至数组列表等。
(7)你甚至可以传入Any类型变量,匹配不同类型常量。
(8)需要注意默认情况处理,case _也需要返回值,如果没有但是又没有匹配到,就抛出运行时错误。默认情况case _不强制要求通配符(只是在不需要变量的值建议这么做),也可以用case abc一个变量来接住,可以什么都不做,可以使用它的值。
(9)通过指定匹配变量的类型(用特定类型变量接住),可以匹配类型而不匹配值,也可以混用。
(10)需要注意类型匹配时由于泛型擦除,可能并不能严格匹配泛型的类型参数,编译器也会报警告。但Array是基本数据类型,对应于java的原生数组类型,能够匹配泛型类型参数。
如果想要表达匹配某个范围的数据,就需要在模式匹配中增加条件守卫
case匹配中可以添加模式守卫,用条件判断来代替精确匹配
实例1:输入i(int类型)时输出”int“+i,输入s(string类型)时输出”string“+s,输入List类型时输出”“List”+list,Array->“array”+array a->"something else"+a
对于数组可以定义多种匹配形式,可以定义模糊的元素类型匹配、元素数量匹配或者精确的某个数组元素值匹配,非常强大。
scala 模式匹配可以对集合进行精确的匹配,例如匹配只有两个元素的、且第一个元素 为 0 的数组。
实例2:依据元素个数进行模式匹配
List匹配和Array差不多,也很灵活。还可用用集合类灵活的运算符来匹配
比如使用::运算符匹配first :: second :: rest,将一个列表拆成三份,第一个第二个元素和剩余元素构成的列表。
注意模式匹配不仅可以通过返回值当做表达式来用,也可以仅执行语句类似于传统
switch-case语句不关心返回值,也可以既执行语句同时也返回
可以匹配n元组、匹配元素类型、匹配元素值。如果只关心某个元素,其他就可以用通配符或变量。
元组大小固定,所以不能用_*。
指定特定元素的值,可以实现类似于循环守卫的功能,相当于加一层筛选。比如for ((10, second) <- tupleList)
元组列表匹配、赋值匹配、for循环中匹配非常灵活,灵活运用可以提高代码可读性。
拓展实例
对象内容匹配。
直接match-case中匹配对应引用变量的话语法是有问题的。编译报错信息提示: 不是样例类也没有一个合法的unapply/unapplySeq成员实现。
要匹配对象,需要实现伴生对象unapply方法,用来对对象属性进行拆解以做匹配。
基本语法:
小结:
➢ 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]]
第二种实现对象匹配的方式是样例类。
case class className定义样例类,会直接将打包apply和拆包unapply的方法直接定义好。
样例类定义中主构造参数列表中的val甚至都可以省略,如果是var的话则不能省略,最好加上的感觉,奇奇怪怪的各种边角简化。
基础语法:
case class Person (name: String, age: Int)
说明:
样例类仍然是类,和普通类相比,只是其自动生成了伴生对象,并且伴生对象中 自动
提供了一些常用的方法,如 apply、unapply、toString、equals、hashCode 和 copy
样例类是为模式匹配而优化的类,因为其默认提供了 unapply 方法,因此,样例 类可
以直接使用模式匹配,而无需自己实现 unapply 方法。
构造器中的每一个参数都成为 val,除非它被显式地声明为 var(不建议这样做)
实例:
偏函数是函数的一种,通过偏函数我们可以方便的对参数做出更精确的检查,例如
偏函数输入类型是List[Int],需要第一个元素是0的集合,也可以通过模式匹配实现的。
通过一个变量定义方式定义,PartialFunction的泛型类型中,前者是参数类型,后者是返回值类型。函数体中用一个case语句来进行模式匹配。上面例子返回输入的List集合中的第二个元素。
偏函数不能像 second(List(1,2,3))这样直接使用,因为这样会直接调用 apply 方法,而应
该调用 applyOrElse 方法,如下
applyOrElse 方法的逻辑为 if (ifDefinedAt(list)) apply(list) else default。如果输入参数满 足条件,即 isDefinedAt 返回 true,则执行 apply 方法,否则执行 defalut 方法,default 方
法 为参数不满足要求的处理逻辑。
一般一个偏函数只能处理输入的一部分场景,实际中往往需要定义多个偏函数用以组合使用。
实例1:
将该 List(1,2,3,4,5,6,"test")中的 Int 类型的元素加一,并去掉字符串。