简介

与default等效的捕获所有的case _ 模式.如果没有模式匹配,抛出MatchError,每个case中,不用break语句.可以在match中使用任何类型,而不仅仅是数字

完全匹配

  1. object CaseDemo extends App {
  2. val arr = Array("111", "222", "333")
  3. val name = arr(Random.nextInt(arr.length))
  4. println(name)
  5. name match {
  6. case "111" => println("111")
  7. case "222" => println("222")
  8. case _ => println("nnnnnnnn")
  9. }
  10. }

类型匹配

  1. object CaseDemo2 extends App {
  2. val arr = Array("hello", 1, -2.0, CaseDemo2)
  3. val elem = arr(2)
  4. println(elem)
  5. elem match {
  6. case x: Int => println("Int " + x)
  7. case y: Double if(y>=0) => println("Double " + y)
  8. case z: String => println("String " + z)
  9. case CaseDemo2 => {
  10. println("case demo 2")
  11. }
  12. case _ => {
  13. println("default")
  14. }
  15. }
  16. # 打印类型
  17. println(elem.getClass.getName)
  18. }

提示: Map类型的泛型在匹配的时候,会自动删除泛型类型,只会匹配到Map类型,而不会精确到Map里面的泛型类型

  1. var obj = Map("a" -> 1)
  2. obj match {
  3. case m1: Map[String, String] => println("这是Map[String, String]")
  4. case m2: Map[String, Int] => println("这是Map[String, Int]")
  5. }
  6. println(obj + " : " + obj.getClass.getName)

数组匹配

  1. object CaseDemo3 extends App {
  2. val arr = Array(0, 1, 7, 0)
  3. arr match {
  4. case Array(1, 5, x, y) => println(x + " " + y)
  5. case Array(1, 1, x, y) => println("only 0")
  6. # 匹配数组从0开始
  7. case Array(0, _*) => println("0...")
  8. case _ => println("something else")
  9. }
  10. }

链表匹配

  1. object CaseDemo4 extends App {
  2. val lst = List(0, 1)
  3. lst match {
  4. //Nil代表空列表 List(0)
  5. case 0 :: Nil => println("only 0")
  6. //s方式拼接字符串
  7. case x :: y :: Nil => println(s"x $x y $y")
  8. case 0 :: a => println(s"0 ... $a")
  9. case _ => println("something else")
  10. }
  11. }

元组匹配

  1. object CaseDemo5 extends App {
  2. val tup = (6, 3, 5)
  3. tup match {
  4. case (1, x, y) => println(s"hello 123 $x, $y")
  5. case (_, z, 5) => println(z)
  6. case _ => println("else")
  7. }
  8. }

类匹配

  1. //可以模式匹配
  2. case class SubmitTask(id: String, name: String)
  3. case class HeartBeat(time: Long)
  4. case object CheckTimeOutTask
  5. object CaseDemo4 extends App {
  6. val arr = Array(CheckTimeOutTask, HeartBeat(123), HeartBeat(88888), new HeartBeat(88888), SubmitTask("0001", "task-0001"))
  7. val a = arr(Random.nextInt(arr.length))
  8. println(a)
  9. a match {
  10. case SubmitTask(id, name) => {
  11. println(s"$id, $name")
  12. }
  13. case HeartBeat(time) => {
  14. println(time)
  15. }
  16. case CheckTimeOutTask => {
  17. println("check")
  18. }
  19. }
  20. }

偏函数

被包在花括号内没有match一组case语句是一个偏函数,它是PartialFunction[A,B]的一个实例,A代表参数类型,B代表返回实例,常用输入模式匹配

  1. object PartialFuncDemo {
  2. //偏函数
  3. def func1: PartialFunction[String, Int] = {
  4. case "one" => 1
  5. case "two" => 2
  6. case _ => -1
  7. }
  8. //其他方式实现
  9. def func2(num: String): Int = num match {
  10. case "one" => 1
  11. case "two" => 2
  12. case _ => -1
  13. }
  14. def main(args: Array[String]): Unit = {
  15. println(func1("one"))
  16. println(func2("one"))
  17. }
  18. }

匿名偏函数

  1. object CaseDemo1 extends App {
  2. // val result = List(1, 2, 3, "heihei", 5).map{case i: Int => i * 2}
  3. val result2 = List(1, 2, 3, "heihei", 5).collect{case i: Int => i * 2}
  4. println(result2)
  5. }

map不能用,因为map不会检查每个元素是不是能应用到这个函数上
函数上有类型约束的,map不检查
collect会检查

输出

  1. List(2, 4, 6, 10)

实现策略

  1. object CaseDemo1 extends App {
  2. val f1 = new PartialFunction[Any, Int] {
  3. //把类型转为Int,并加1
  4. def apply(any: Any) = any.asInstanceOf[Int] + 1
  5. //检查类型
  6. def isDefinedAt(any: Any) = if (any.isInstanceOf[Int]) true else false
  7. }
  8. //collect会调用isDefinedAt,map不会
  9. val result = List(1, 3, 5, "seven") collect f1
  10. println(result)
  11. }

守卫

像if表达式一样,match也提供守卫功能,守卫可以是任何boolean条件

  1. val ch = 3
  2. var sign = 0
  3. ch match {
  4. case '+' => sign = '+'
  5. case '-' => sign = '-'
  6. case _ if ch.toString.equals("3") => sign = 3
  7. case _ => sign = -1
  8. }
  9. println(sign)

模式中的变量

如果在case关键字后面跟变量名,那么match前表达式的值会赋给那个变量

  1. def match2() = {
  2. for (c <- "+-*/123") {
  3. c match {
  4. case value if Character.isDigit(c) => println("这是一个数字: " + value)
  5. case '+' => println("这次字符为+号")
  6. case '-' => println("这次字符为-号")
  7. case '*' => println("这次字符为*号")
  8. case '/' => println("这次字符为/号")
  9. case _ => println("通配")
  10. }
  11. }
  12. }
  13. match2()

提取器

模式匹配什么才算匹配呢?
即,case中unapply方法返回some集合则为匹配成功,返回none集合则为匹配失败.

unapply
调用unapply,传入number
接收返回值判断返回值是None还是Some
如果是Some,则将其解开,并将其中值赋值给n(就是case Square(n)中的n)

  1. object Square {
  2. def unapply(z: Double): Option[Double] = Some(math.sqrt(z))
  3. }
  4. object CaseDemo2 extends App {
  5. var n = 36.0
  6. n match {
  7. case Square(result) => println(s" ${n} + ",s" + ${result}")
  8. }
  9. }

输出

  1. ( 36.0 + , + 6.0)

变量声明中的模式

match中每一个case都可以单独提取出来,意思是一样的

  1. val (x, y) = (1, 2)
  2. println(x, y)
  3. val (q, r) = BigInt(10) /% 3
  4. println(q, r)
  5. val arr = Array(1, 7, 2, 9)
  6. val Array(first, second, _*) = arr
  7. println(first, second)

输出

  1. (1,2)
  2. (3,1)
  3. (1,7)

for表达式中的模式

  1. import scala.collection.JavaConverters._
  2. for ((k, v) <- System.getProperties.asScala) {
  3. println(k + " -> " + v)
  4. }

中置表达式

什么是一个中置表达式? 1+2,这就是一个中置表达式.
如果unapply方法产出一个元组,你可以在case语句中使用中置表示法.比如可以匹配一个List序列

  1. val list = List(1, 2, 3, 4, 5, 6)
  2. list match {
  3. case l1 :: l2 :: l3 => println(l1 + " , " + l2 + " , " + l3)
  4. }

从左到有,多的就变为list
输出

  1. 1 , 2 , List(3, 4, 5, 6)

嵌套类

  1. abstract class Item
  2. case class Article(description: String, price: Double) extends Item
  3. //Item*表示可以多个
  4. case class Bundle(description: String, discount: Double, item: Item*) extends Item
  5. object CaseDemo extends App {
  6. def match9() = {
  7. val sale = Bundle("愚人节大甩卖系列", 10,
  8. Article("<<九阴真经>>", 40),
  9. Bundle("从出门一条狗到装备全发光", 20,
  10. Article("如何快速捡起地上装备", 80),
  11. Article("名字起的太长", 30)))
  12. val result = sale match {
  13. case Bundle(_, _, Article(descr, _), _*) => descr
  14. }
  15. println(result)
  16. }
  17. match9()
  18. }

输出

  1. <<九阴真经>>

如果要输出后面可以这样

  1. val result = sale match {
  2. case Bundle(_, _, Article(descr, _), temp @ _*) => temp
  3. }

输出

  1. WrappedArray(Bundle(从出门一条狗到装备全发光,20.0,WrappedArray(Article(如何快速捡起地上装备,80.0), Article(名字起的太长,30.0))))

通过@表示法将嵌套的值绑定到变量
_*绑定剩余Item到temp