当前位置: 首页 > 工具软件 > Match > 使用案例 >

【Scala】match——模式匹配总结

俞新翰
2023-12-01

一、基本语法

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))
      } 
    }

二、显式模式匹配

1、匹配常量

def describe(x: Any) = x match {
 case 5 => "Int five"
 case "hello" => "String hello"
 case true => "Boolean true"
 case '+' => "Char +"
}

2、匹配类型

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
}

3、匹配数组

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)
      }
}

4、匹配列表

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)
      }
}

5、匹配元组

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)
      }
}

6、匹配对象

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、 上述匹配对象的案例使用样例类会节省大量代码
 

三、隐式模式匹配

1、变量声明中的模式匹配

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")
}

2、for 表达式中的模式匹配

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
      }
}

3、偏函数中的模式匹配

    // 偏函数的应用,求绝对值
    // 对输入数据分为不同的情形:正、负、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))

 类似资料: