经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » Java相关 » Scala » 查看文章
12. Scala模式匹配
来源:cnblogs  作者:铖歌  时间:2019/5/17 8:50:35  对本文有异议

12.1 match 

  12.1.1 基本介绍 

      Scala中的模式匹配类似于Java中的switch语法,但是更加强大

      模式匹配语法中,采用match关键字声明,每个分支采用case关键字进行声明,当需要匹配时,会从第一个case分支开始,如果匹配成功,那么执行对应的逻辑代码,如果匹配不成功,继续执行下一个分支进行判断。如果所有的case都不匹配,那么会执行case_分支,类似于Java中的default语句

  12.1.2 scala的match的快速入门案例 

  1. object boke_demo01 {
  2.  
  3. def main(args: Array[String]): Unit = {
  4. val oper = '+'
  5. val n1 = 20
  6. val n2 = 10
  7. var res = 0
  8. //说明
  9. //1. match (类似java switch) 和 case 是关键字
  10. //2. 如果匹配成功, 则 执行 => 后面的代码块.
  11. //3. 匹配的顺序是从上到下,匹配到一个就执行对应的 代码
  12. //4. => 后面的代码块 不要写 break ,会自动的退出match
  13. //5. 如果一个都没有匹配到,则执行 case _ 后面的代码块
  14. oper match {
  15. case '+' => {
  16. res = n1 + n2
  17. println("ok~~")
  18. println("hello~~")
  19. }
  20. case '-' => res = n1 - n2
  21. case '*' => res = n1 * n2
  22. case '/' => res = n1 / n2
  23. case 1 => println("匹配到1")
  24. case 1.1 => println("匹配1.1")
  25. case _ => println("oper error")
  26. }
  27. println("res=" + res)
  28.  
  29. }
  30. }

  12.1.3 match的细节和注意事项  

      1) 如果所有case都不匹配,那么会执行case_分支,类似于Java中的default语句

      2) 如果所有case都不匹配,又没有写case_分支,那么会抛出MatchError

      3) 每个case中,不用break语句,自动中断case

      4) 可以在match中使用其它类型,而不仅仅是字符

      5) => 等价于 java switch的 :

      6) => 后面的代码块到下一个case,是作为一个整体执行,可以使用{}扩起来,也可以不扩

12.2 守卫

  12.2.1 基本介绍 

      如果想要表达匹配某个范围的数据,就需要在模式匹配中增加条件守卫

  12.2.2 应用案例  

  1. object boke_demo01 {
  2.  
  3. def main(args: Array[String]): Unit = {
  4.  
  5. for (ch <- "+-3!") { //是对"+-3!" 遍历
  6. var sign = 0
  7. var digit = 0
  8. ch match {
  9. case '+' => sign = 1
  10. case '-' => sign = -1
  11. // 说明..
  12. // 如果 case 后有 条件守卫即if ,那么这时的 _ 不是表示默认匹配
  13. // 表示忽略 传入 的 ch
  14. case _ if ch.toString.equals("3") => digit = 3
  15. case _ => sign = 2
  16. }
  17. //分析
  18. // + 1 0
  19. // - -1 0
  20. // 3 0 3
  21. // ! 2 0
  22. println(ch + " " + sign + " " + digit)
  23. }
  24.  
  25. }
  26. }

12.3 模式中的变量 

  12.3.1 基本介绍  

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

  12.3.2 应用案例 

  1. object boke_demo01 {
  2.  
  3. def main(args: Array[String]): Unit = {
  4. val ch = 'U'
  5. ch match {
  6. case '+' => println("ok~")
  7. // 下面 case mychar 含义是 mychar = ch
  8. case mychar => println("ok~" + mychar)
  9. case _ => println("ok~~")
  10. }
  11.  
  12. val ch1 = '+'
  13. //match是一个表达式,因此可以有返回值
  14. //返回值就是匹配到的代码块的最后一句话的值
  15. val res = ch1 match {
  16. case '+' => ch1 + " hello "
  17. case _ => println("ok~~")
  18. }
  19.  
  20. println("res=" + res)
  21. }
  22. }

12.4 类型匹配 

  12.4.1 基本介绍 

      可以匹配对象的任意类型,这样做避免了使用isInstanceOf和asInstanceOf

  12.4.2 应用案例 

  1. object boke_demo01 {
  2.  
  3. def main(args: Array[String]): Unit = {
  4. val a = 8
  5. //说明 obj 实例的类型 根据 a 的值来返回
  6. val obj = if (a == 1) 1
  7. else if (a == 2) "2"
  8. else if (a == 3) BigInt(3)
  9. else if (a == 4) Map("aa" -> 1)
  10. else if (a == 5) Map(1 -> "aa")
  11. else if (a == 6) Array(1, 2, 3)
  12. else if (a == 7) Array("aa", 1)
  13. else if (a == 8) Array("aa")
  14.  
  15. //说明
  16. //1. 根据 obj 的类型来匹配
  17. // 返回值
  18. val result = obj match {
  19.  
  20. case a: Int => a
  21. case b: Map[String, Int] => "对象是一个字符串-数字的Map集合"
  22. case c: Map[Int, String] => "对象是一个数字-字符串的Map集合"
  23. case d: Array[String] => d //"对象是一个字符串数组"
  24. case e: Array[Int] => "对象是一个数字数组"
  25. case f: BigInt => Int.MaxValue
  26. case y: Float => println("xx")
  27. case _ => "啥也不是"
  28. }
  29.  
  30. println(result)
  31.  
  32. }
  33. }

  12.4.3 类型匹配注意事项 

      1) Map[String, Int]和Map[Int, String]是两种不同的类型,其它类推

      2) 在进行类型匹配时,编译器会预先检测是否有可能的匹配,如果没有则报错

  1. object boke_demo01 {
  2.  
  3. def main(args: Array[String]): Unit = {
  4.  
  5. val obj = 10
  6. val result = obj match {
  7. case a: Int => a
  8. //case b: Map[String, Int] => "Map集合" //取消注释之后会报错
  9. case _ => "啥也不是"
  10. }
  11.  
  12. }
  13. }

      4) 如果case _ 出现在match中间,则表示隐藏变量名,即不使用,而不是表示默认匹配

        

12.5 匹配数组 

  12.5.1 基本介绍 

      1) Array(0)匹配只有一个元素且为0的数组

      2) Array(x,y)匹配数组有两个元素,并将两个元素赋值为x和y。当然可以依次类推Array(x,y,z)匹配数组有三个元素,等等

      3) Array(0,_*)匹配数组以0开始

  12.5.2 应用案例 

  1. import scala.collection.mutable.ArrayBuffer
  2.  
  3. object boke_demo01 {
  4.  
  5. def main(args: Array[String]): Unit = {
  6.  
  7. // val arrs = Array(Array(0), Array(1, 0), Array(0, 1, 0),
  8. // Array(1, 1, 0), Array(1, 1, 0, 1))
  9. //
  10. // for (arr <- arrs ) {
  11. // val result = arr match {
  12. // case Array(0) => "0"
  13. // case Array(x, y) => x + "=" + y
  14. // case Array(0, _*) => "以0开头和数组"
  15. // case _ => "什么集合都不是"
  16. // }
  17. // // result = 0
  18. // // result = 1 = 0
  19. // // result = 以0开头和数组
  20. // // result = 什么集合都不是
  21. // // result = 什么集合都不是
  22. // println("result = " + result)
  23. // }
  24.  
  25. //给你一个数组集合,如果该数组是 Array(10,20) , 请使用默认匹配,返回Array(20,10)
  26.  
  27.  
  28. val arrs2 = Array(Array(0), Array(1, 0), Array(0, 1, 0),
  29. Array(1, 1, 0), Array(1, 1, 0, 1))
  30.  
  31. for (arr <- arrs2) {
  32. val result = arr match {
  33. //case Array(0) => "0"
  34. case Array(x, y) => ArrayBuffer(y, x) //Array(y,x).toBuffer //? ArrayB(y,x)
  35. //case Array(0, _*) => "以0开头和数组"
  36. case _ => "不处理~~"
  37. }
  38.  
  39. println("res=" + result) //ArrayBuffer(0,1)
  40. }
  41.  
  42. }
  43. }

12.6 匹配列表 

      -案例演示

  1. object boke_demo01 {
  2.  
  3. def main(args: Array[String]): Unit = {
  4.  
  5. for (list <- Array(List(0), List(1, 0), List(0, 0, 0), List(1, 0, 0))) {
  6. val result = list match {
  7. case 0 :: Nil => "0" //
  8. case x :: y :: Nil => x + " " + y //
  9. case 0 :: tail => "0 ..." //
  10. case x :: Nil => x
  11. case _ => "something else"
  12. }
  13. //1. 0
  14. //2. 1 0
  15. //3. 0 ...
  16. //4. something else
  17. println(result)
  18. }
  19.  
  20. }
  21. }

12.7 匹配元组 

      -案例演示

  1. object boke_demo01 {
  2.  
  3. def main(args: Array[String]): Unit = {
  4. //如果要匹配 (10, 30) 这样任意两个元素的对偶元组,应该如何写
  5. for (pair <- Array((0, 1), (1, 0), (10, 30), (1, 1), (1, 0, 2))) {
  6. val result = pair match { //
  7. case (0, _) => "0 ..." //
  8. case (y, 0) => y //
  9. case (x, y) => (y, x) //"匹配到(x,y)" + x + " " + y
  10. case _ => "other" //.
  11. }
  12. //1. 0 ...
  13. //2. 1
  14. //3. (30,10)
  15. //4. (1,1)
  16. //5. other
  17. println(result)
  18. }
  19.  
  20. }
  21. }

12.8 对象匹配 

  12.8.1 基本介绍 

      对象匹配,什么才算是匹配呢?规则如下:

        1) case中对象的unapply方法(对象提取器)返回Some集合则为匹配成功

        2) 返回None集合则为匹配失败

  12.8.2 快速入门 

  1. object boke_demo01 {
  2.  
  3. def main(args: Array[String]): Unit = {
  4.  
  5. // 模式匹配使用:
  6. val number: Double = Square(6.0) // 36.0 //
  7.  
  8. number match {
  9. //说明 case Square(n) 的运行的机制
  10. //1. 当匹配到 case Square(n)
  11. //2. 调用Square 的 unapply(z: Double),z 的值就是 number
  12. //3. 如果对象提取器 unapply(z: Double) 返回的是Some(6) ,则表示匹配成功,同时
  13. // 将6 赋给 Square(n) 的n
  14. //4. 果对象提取器 unapply(z: Double) 返回的是None ,则表示匹配不成功
  15. case Square(n) => println("匹配成功 n=" + n)
  16. case _ => println("nothing matched")
  17. }
  18.  
  19.  
  20. }
  21. }
  22.  
  23. //说明
  24.  
  25. object Square {
  26. //说明
  27. //1. unapply方法是对象提取器
  28. //2. 接收z:Double 类型
  29. //3. 返回类型是Option[Double]
  30. //4. 返回的值是 Some(math.sqrt(z)) 返回z的开平方的值,并放入到Some(x)
  31. def unapply(z: Double): Option[Double] = {
  32. println("unapply被调用 z 是=" + z)
  33. Some(math.sqrt(z))
  34. //None
  35. }
  36.  
  37. def apply(z: Double): Double = z * z
  38. }

  12.8.3 应用案例2 

      -案例演示

  1. object boke_demo01 {
  2.  
  3. def main(args: Array[String]): Unit = {
  4.  
  5. val namesString = "Alice,Tom,Jack" //字符串
  6. //说明
  7. namesString match {
  8. // 当 执行 case Names(first, second, third)
  9. // 1. 会调用 unapplySeq(str),把 "Alice,Tom,Jack" 传入给 str
  10. // 2. 如果 返回的是 Some("Alice","Tom","Jack"),分别给 (first, second, third)
  11. // 注意,这里的返回的值的个数需要和 (first, second, third)要一样
  12. // 3. 如果返回的None ,表示匹配失败
  13.  
  14. case Names(first, second, third) => {
  15. println("the string contains three people's names")
  16. // 打印字符串
  17. println(s"$first $second $third")
  18. }
  19. case _ => println("nothing matched")
  20. }
  21.  
  22. }
  23. }
  24.  
  25. //object
  26. object Names {
  27. //当构造器是多个参数时,就会触发这个对象提取器
  28. def unapplySeq(str: String): Option[Seq[String]] = {
  29. if (str.contains(",")) Some(str.split(","))
  30. else None
  31. }
  32. }

      -案例演示小结

        1) 当case后面的对象提取器方法的参数为多个,则会默认调用def unapplySeq()方法

        2) 如果unapplySeq返回的是Some,获取其中的值,判断得到的sequence中的元素的个数是否是三个,如果是三个,则把三个元素分别取出,赋值给first,second和third

        3) 其它的规则不变

12.9 变量声明中的模式  

  12.9.1 基本介绍 

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

  12.9.2 应用案例 

  1. object boke_demo01 {
  2.  
  3. def main(args: Array[String]): Unit = {
  4.  
  5. val (x, y, z) = (1, 2, "hello")
  6. println("x=" + x)
  7. val (q, r) = BigInt(10) /% 3 //说明 q = BigInt(10) / 3 r = BigInt(10) % 3
  8. val arr = Array(1, 7, 2, 9)
  9. val Array(first, second, _*) = arr // 提出arr的前两个元素
  10. println(first, second)
  11.  
  12. }
  13. }

12.10 for表达式中的模式 

  12.10.1 基本介绍 

      for循环也可以进行模式匹配

  12.10.2 应用案例 

  1. object boke_demo01 {
  2.  
  3. def main(args: Array[String]): Unit = {
  4. val map = Map("A" -> 1, "B" -> 0, "C" -> 3)
  5. for ((k, v) <- map) {
  6. println(k + " -> " + v) // 出来三个key-value ("A"->1), ("B"->0), ("C"->3)
  7. }
  8. //说明 : 只遍历出 value =0 的key-value ,其它的过滤掉
  9. println("--------------(k, 0) <- map-------------------")
  10. for ((k, 0) <- map) {
  11. println(k + " --> " + 0)
  12. }
  13.  
  14. //说明, 这个就是上面代码的另外写法, 只是下面的用法灵活和强大
  15. println("--------------(k, v) <- map if v == 0-------------------")
  16. for ((k, v) <- map if v >= 1) {
  17. println(k + " ---> " + v)
  18. }
  19.  
  20. }
  21. }

12.11 样例(模版)类 

  12.11.1 样例类快速入门 

  1. object CaseClassDemo01 {
  2. def main(args: Array[String]): Unit = {
  3. println("hello~~")
  4. }
  5. }
  6.  
  7. abstract class Amount
  8. case class Dollar(value: Double) extends Amount //样例类
  9. case class Currency(value: Double, unit: String) extends Amount //样例类
  10. case object NoAmount extends Amount //样例类

  12.11.2 基本介绍 

      1) 样例类仍然是类

      2) 样例类用case关键字进行声明

      3) 样例类是为模式匹配而优化的类

      4) 构造器中的每一个参数都成为val-除非它被显式地声明为var(不建议这样做)

      5) 在样例类对应的伴生对象中提供apply方法,不用new关键字就能构造出相应的对象

      6) 提供unapply方法让模式匹配可以工作

      7) 将自动生成toString、equals、hashCode和copy方法(有点类似模版类,直接给生成,供程序员使用)

      8) 除上述外,样例类和其它类完全一样。可以添加字段和方法,扩展它们

  12.11.3 应用案例1 

      -案例演示

  1. object boke_demo01 {
  2.  
  3. def main(args: Array[String]): Unit = {
  4. //该案例的作用就是体验使用样例类方式进行对象匹配简洁性
  5. for (amt <- Array(Dollar(1000.0), Currency(1000.0, "RMB"), NoAmount)) {
  6. val result = amt match {
  7. //说明
  8. case Dollar(v) => "$" + v // $1000.0
  9. //说明
  10. case Currency(v, u) => v + " " + u // 1000.0 RMB
  11. case NoAmount => "NoAmount" // NoAmount
  12. }
  13. println(amt + ": " + result)
  14. }
  15.  
  16. }
  17. }
  18.  
  19. abstract class Amount
  20.  
  21. case class Dollar(value: Double) extends Amount //样例类
  22. case class Currency(value: Double, unit: String) extends Amount //样例类
  23. case object NoAmount extends Amount //样例类

  12.11.4 应用案例2 

      -说明

        样例类的copy方法和带名参数

        copy创建一个与现有对象值相同的新对象,并可以通过带名参数来修改某些属性

      -案例演示

  1. object boke_demo01 {
  2.  
  3. def main(args: Array[String]): Unit = {
  4. val amt = new Currency(3000.0, "RMB")
  5. val amt2 = amt.copy() // 克隆,创建的对象和amt的属性一样
  6. println("amt2.value" + amt2.value + " amt2.unit= " + amt2.unit)
  7. println(amt2)
  8.  
  9. val amt3 = amt.copy(value = 8000.0)
  10. println(amt3)
  11.  
  12. val amt4 = amt.copy(unit = "美元")
  13. println(amt4)
  14. }
  15. }
  16.  
  17.  
  18. abstract class Amount
  19.  
  20. case class Dollar(value: Double) extends Amount //样例类
  21. case class Currency(value: Double, unit: String) extends Amount //样例类
  22. case object NoAmount extends Amount //样例类

12.12 case语句的中置(缀)表达式 

  12.12.1 基本介绍 

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

  12.12.2 应用案例 

      -案例演示

  1. object boke_demo01 {
  2.  
  3. def main(args: Array[String]): Unit = {
  4. List(1, 3, 5, 9) match { //修改并测试
  5. //1.两个元素间::叫中置表达式,至少first,second两个匹配才行.
  6. //2.first 匹配第一个 second 匹配第二个, rest 匹配剩余部分(5,9)
  7. case first :: second :: rest => println(first + " " + second + " " + rest.length + " " + rest) //
  8. case _ => println("匹配不到...")
  9. }
  10.  
  11. }
  12. }

12.13 密封类 

  12.13.1 基本介绍 

      1) 如果想让case类的所有子类都必须在申明该类的相同的源文件中定义,可以将样例类的通用超类声明为sealed,这个超类称之为密封类

      2) 密封就是不能在其它文件中定义子类

      

 

原文链接:http://www.cnblogs.com/zhanghuicheng/p/10867153.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号