zoukankan      html  css  js  c++  java
  • Scala(八)模式匹配

    模式匹配

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

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

    8.1 基本语法

    package com.yuange.scala.day05
    
    object TestMatchCase {
      def main(args: Array[String]): Unit = {
        var a: Int = 10
        var b: Int = 20
        var operator: Char = '*'
    
        var result = operator match {
          case '+' => a +b
          case '-' => a - b
          case '*' => a * b
          case '/' => a / b
          case _ => "其他字符"
        }
        println("result=" + result)
      }
    }

      (1)如果所有case都不匹配,那么会执行case _ 分支,类似于Javadefault语句,若没有case _ 分支,那么会抛出MatchError

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

      (3match case语句可以匹配任何类型,而不只是字面量。

      (4=> 后面的代码块,是作为一个整体执行,可以使用{}括起来,也可以不括。

    8.2 模式守卫

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

      2)案例实操

    package com.yuange.scala.day05
    
    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 _ => "其他类型"
        }
        println(abs(-10))
      }
    }

    8.3 模式匹配类型

    8.3.1 匹配常量

      1scala中,模式匹配可以匹配所有的字面量,包括字符串,字符,数字,布尔值等等。

      2)实操

    package com.yuange.scala.day05
    
    object TestMatchVal {
      def main(args: Array[String]): Unit = {
        println(describe('+'))
      }
    
      def describe(x: Any) = x match {
        case 5 => "Int 5"
        case "hello" => "String hello"
        case true => "Boolean true"
        case '+' => "Char +"
      }
    }

    8.3.2 匹配类型

      1需要进行类型判断时,可以使用前文所学的isInstanceOf[T]asInstanceOf[T],也可使用模式匹配实现同样的功能。

      2)案例实操

    package com.yuange.scala.day05
    
    object TestMatchClass {
      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
      }
    
      def main(args: Array[String]): Unit = {
        //泛型擦除
        println(describe(List(1,3,5,7,9)))
        //数组除外,可保留泛型
        println(describe(Array(1,3,5,7,9)))
        println(describe(Array("abcdefg")))
      }
    }

    8.3.3 匹配数组

      1scala模式匹配可以对集合进行精确的匹配,例如匹配只有两个元素的、且第一个元素为0的数组。

      2案例实操

    package com.yuange.scala.day05
    
    object TestMatchArray {
      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"
            case Array(x,y) => x + "," + y  //匹配有两个元素的数组,然后把元素赋值给对应的x,y
            case Array(0,_*) => "以0开头的数组"
            case _ => "其他"
          }
          println("result=" + result)
        }
      }
    }

    8.3.4 匹配列表

      1)方式一

    package com.yuange.scala.day05
    
    object TestMatchList {
      def main(args: Array[String]): Unit = {
        for(i <- Array(List(0),List(1,0),List(0,0,0),List(1,0,0),List(88))){
          var result = i match {
            case List(0) => "0"
            case List(x,y) => x + "," + y
            case List(0,_*) => "0 ..."
            case _ => "其他"
          }
          println("result=" + result)
        }
      }
    }

      2)方式二

    package com.yuange.scala.day05
    
    object TestMatchListTwo {
      def main(args: Array[String]): Unit = {
        val testList = List(1,2,3,4,5)
    
        testList match {
          case one :: two :: three => println(one + "-" + two + "-" + three)
          case _ => println("其他")
        }
      }
    }

    8.3.5 匹配元组

    package com.yuange.scala.day05
    
    object TestMatchTuple {
      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 _ => "其他"
          }
          println("result=" + result)
        }
      }
    }

    8.3.6 匹配对象及样例类

      1)基本语法

    package com.yuange.scala.day05
    
    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",18)
        var result = user match {
          case User("zhangsan",18) => "正确"
          case _ => "错误"
        }
        println("result=" + result)
      }
    }

        小结:

        (1)val user = User("zhangsan",11),该语句在执行时,实际调用的是User伴生对象中的apply方法,因此不用new关键字就能构造出相应的对象。

        (2)当将User("zhangsan", 11)写在case后时[case User("zhangsan", 18) => "正确"],会默认调用unapply方法(对象提取器)user作为unapply方法的参数unapply方法将user对象的nameage属性提取出来,与User("zhangsan", 11)中的属性值进行匹配

        (3)case中对象的unapply方法(提取器)返回Some,且所有属性均一致,才算匹配成功,属性不一致,或返回None,则匹配失败。

        (4)若只提取对象的一个属性,则提取器为unapply(obj:Obj):Option[T]

        (5)若提取对象的多个属性,则提取器为unapply(obj:Obj):Option[(T1,T2,T3…)]

        (6)若提取对象的可变个属性,则提取器为unapplySeq(obj:Obj):Option[Seq[T]]

      2)样例类

        (1)语法:

    case class Person (name: String, age: Int)

        (2)说明:

          1、样例类仍然是类,和普通类相比,只是其自动生成了伴生对象,并且伴生对象中自动提供了一些常用的方法,如applyunapplytoStringequalshashCodecopy

          2、样例类是为模式匹配而优化的类,因为其默认提供了unapply方法,因此,样例类可以直接使用模式匹配,而无需自己实现unapply方法。

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

        (3)实操

    package com.yuange.scala.day05
    
    case class User2(name: String,age: Int)
    
    object TestMatchUnapplyTwo {
      def main(args: Array[String]): Unit = {
        val user2: User2 = User2("lisi",19)
        var result = user2 match{
          case User2("lisi",19) => "正确"
          case _ => "错误"
        }
        println("result= " + result)
      }
    }

    8.4 变量声明中的模式匹配

    package com.yuange.scala.day05
    
    case class Person(name: String,age: Int)
    
    object TestMatchVariable {
      def main(args: Array[String]): Unit = {
        val (x,y) = (1,2)
        println(s"x=$x,y=$y")
    
        val Array(one,two,_*) = Array(1,3,5,7,9)
        println(s"one=$one,two=$two")
    
        val Person(name,age) = Person("张三",19)
        println(s"name=$name,age=$age")
      }
    }

    8.5 for表达式中的模式匹配

    package com.yuange.scala.day05
    
    object TestMatchFor {
      def main(args: Array[String]): Unit = {
        val testMap = Map("zhangsan"->1001,"lisi"->1002,"wangwu"->1003)
        for ((k,v) <- testMap){
          println(k + ":" + v)
        }
        println("-"*100)
        //遍历value=1001的k-v,若v不是1001,则过滤
        for((k,1001) <- testMap){
          println(k + ":" + "1001")
        }
        println("-"*100)
        //守卫
        for((k,v) <- testMap if v >= 1002){
          println(k + ":" + v)
        }
      }
    }

    8.6 偏函数中的模式匹配

      偏函数也是函数的一种,通过偏函数我们可以方便的对输入参数做更精确的检查。例如该偏函数的输入类型为List[Int],而我们需要的是第一个元素是0的集合,这就是通过模式匹配实现的。

      1) 偏函数定义(该偏函数的功能是返回输入的List集合的第二个元素)

    val second: PartialFunction[List[Int], Option[Int]] = {
      case x :: y :: _ => Some(y)
    } 

      2)偏函数原理

        上述代码会被scala编译器翻译成以下代码,与普通函数相比,只是多了一个用于参数检查的函数——isDefinedAt,其返回值类型为Boolean

    val second = new PartialFunction[List[Int], Option[Int]] {
        //检查输入参数是否合格
        override def isDefinedAt(list: List[Int]): Boolean = list match {
          case x :: y :: _ => true
          case _ => false
        }
        
        //执行函数逻辑
        override def apply(list: List[Int]): Option[Int] = list match {
          case x :: y :: _ => Some(y)
        }
      }

      3)偏函数使用

        偏函数不能像second(List(1,2,3))这样直接使用,因为这样会直接调用apply方法,而应该调用applyOrElse方法,如下:

    second.applyOrElse(List(1,2,3), (_: List[Int]) => None)

        applyOrElse方法的逻辑为 if (ifDefinedAt(list)) apply(list) else default。如果输入参数满足条件,即isDefinedAt返回true,则执行apply方法,否则执行defalut方法,default方法为参数不满足要求的处理逻辑。

      4) 案例实操

        (1)需求:将该List(1,2,3,4,5,6,"test")中的Int类型的元素加一,并去掉字符串。

        (2)实操

          方法一:

    List(1,2,3,4,5,6,"test").filter(_.isInstanceOf[Int]).map(_.asInstanceOf[Int] + 1).foreach(println)

          方法二:

    List(1, 2, 3, 4, 5, 6, "test").collect { case x: Int => x + 1 }.foreach(println)
  • 相关阅读:
    C/C++各种类型int、long、double、char表示范围(最大和最小)
    XSS学习笔记(五)-XSS防御
    组态Log4j(非常具体的)
    C#抽象类其中创建一个静态方法
    DirectSound应用
    谈论Hibernate级联删除——JPA根据Hibernate实现许多级联删除CascadeType.DELETE_ORPHAN
    failed to open stream: HTTP request failed! HTTP/1.1 404 Not Found
    英语语法总结---一、英语中定语放在哪
    windows常用命令有哪些(整理)
    css如何实现垂直居中(5种方法)
  • 原文地址:https://www.cnblogs.com/LzMingYueShanPao/p/14805978.html
Copyright © 2011-2022 走看看