Scala 中的模式匹配 类似于 Java 中的 switch 语法模式匹配语法中,采用 match 关键字声明,每个分支采用 case 关键字进行声明,当需要匹配时,会从第一个 case 分支开始,如果匹配成功,那么执行对应的逻辑代码,如果匹配不成功,继续执行下一个分支进行判断。如果所有 case 都不匹配,那么会执行 case _ 分支, 类似于 Java 中 default 语句。模式守卫如果想要表达匹配某个范围的数据,就需要在模式匹配中增加条件守卫。我个人将模式匹配分为两类,一类是出现“match”关键字,另一类不使用match关键字,也能实现模式匹配的思想,为了方便记忆,将第一类称为“显式模式匹配”,第二类称为“隐式模式匹配”。
案例:
object TestMatchGuard {
def main(args: Array[String]): Unit = {
// 求绝对值
def abs(x: Int) = x match { // 模式匹配
case i: Int if i >= 0 => i // 增加匹配条件——模式守卫
case j: Int if j < 0 => -j
case _ => "type illegal"
}
println(abs(-5))
}
}
def describe(x: Any) = x match {
case 5 => "Int five"
case "hello" => "String hello"
case true => "Boolean true"
case '+' => "Char +"
}
def describe(x: Any) = x match {
case i: Int => "Int"
case s: String => "String hello"
case m: List[_] => "List"
case c: Array[Int] => "Array[Int]"
case someThing => "something else " + someThing
}
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 //匹配有两个元素的数组
case Array(0, _*) => "以 0 开头的数组" //匹配以 0 开头和数组
case _ => "something else"
}
println("result = " + result)
}
}
def main(args: Array[String]): Unit = {
//list 是一个存放 List 集合的数组
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 //匹配有两个元素的 List
case List(0, _*) => "0 ..."
case _ => "something else"
}
println(result)
}
}
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 + " " + b
case _ => "something else" //默认
}
println(result)
}
}
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)
None
else
Some(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) => "yes"
case _ => "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] ]
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) => "yes"
case _ => "no"
}
println(result)
}
}
说明:
1、 样例类仍然是类,和普通类相比,只是其自动生成了伴生对象,并且伴生对象中自动提供了一些常用的方法,如 apply 、 unapply 、 toString 、 equals 、 hashCode 和 copy 。2、 样例类是为模式匹配而优化的类,因为其默认提供了 unapply 方法,因此,样例类可以直接使用模式匹配,而无需自己实现 unapply 方法。3、 上述匹配对象的案例使用样例类会节省大量代码
def main(args: Array[String]): Unit = {
val (x, y) = (1, 2)
println(s"x=$x,y=$y")
val Array(first, second, _*) = Array(1, 7, 2, 9)
println(s"first=$first,second=$second")
val Person(name, age) = Person1("zhangsan", 16)
println(s"name=$name,age=$age")
}
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
}
}
// 偏函数的应用,求绝对值
// 对输入数据分为不同的情形:正、负、0
val positiveAbs: PartialFunction[Int, Int] = {
case x if x > 0 => x
}
val negativeAbs: PartialFunction[Int, Int] = {
case x if x < 0 => -x
}
val zeroAbs: PartialFunction[Int, Int] = {
case 0 => 0
}
def abs(x: Int): Int = (positiveAbs orElse negativeAbs orElse zeroAbs) (x)
println(abs(-67))
println(abs(35))
println(abs(0))