一、基本语法

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、 样例类仍然是类,和普通类相比,只是其自动生成了伴生对象,并且伴生对象中

自动提供了一些常用的方法,如 applyunapplytoString 、 equals 、 hashCode 和 copy 。


2、 样例类是为模式匹配而优化的类,因为其默认提供了 unapply 方法,因此,样例

类可以直接使用模式匹配,而无需自己实现 unapply 方法。

 

上述匹配对象的案例使用样例类会节省大量代码

 


三、隐式模式匹配

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