zoukankan      html  css  js  c++  java
  • Scala match模式匹配

    一、简单匹配

    1.基本语法

    匹配字面量
    ①case _ :默认匹配
    ②如果没有匹配到任何case,则会抛出异常scala.MatchError
    ③=>后如果有多个语句,可以加大括号,也可不加
    ④模式匹配可以有返回值

    def main(args: Array[String]): Unit = {
      val n1 = 7
      val n2 = 8
      val ch = '+'
    
      val res = ch match {
        case '+' => n1 + n2
        case '-' => n1 - n2
        case _ =>
          println("sorry")
          println("没有匹配到")
      }
    
      println(res)
    }
    

    2.条件守卫,if后的括号可以省略

    def main(args: Array[String]): Unit = {
      val num = 8
    
      num match {
        case _ if num < 5 => println("小于5")
        case _ if num > 5 => println("大于5")
        case _ => println("default")
      }
    }
    

    3.match中匹配变量

    def main(args: Array[String]): Unit = {
      val name = "mo"
    
      name match {
        //将name的值赋给myName,此时这个case一定会匹配到
        case myName => println(myName)
      }
    }

    4.变量类型匹配

    ①只有类型相同的变量才会匹配到

    ②匹配到的时候,相当于自动做了obj.isInstanceOf和obj.asInstanceOf的操作

    def main(args: Array[String]): Unit = {
      val num = 3
      val obj = if (num == 1) Array("abc", "def", "xyz")
      else if (num == 2) Array(1, 2, 3)
      else if (num == 3) Map("abc" -> 1, "def" -> 2)
    
      obj match {
        case c: Array[String] => println(c.mkString(","))
        case c: Array[Int] => println(c.mkString(","))
        case c: Map[String, Int] => println(c)
        //只判断类型,不接收值
        case _: String => println("xx")
        case _ => println("啥也不是")
      }
      
    }
    

    二、集合匹配

    1.数组匹配

    def main(args: Array[String]): Unit = {
      val array = Array(Array(1), Array(1, 2), Array(1, 2, 3))
    
      for (item <- array) {
        val res = item match {
          case Array(1) => 1
          case Array(x, y) => x + "," + y
          case Array(1, _*) => "以1开头的数组"
          case _ => "default"
        }
    
        println(res)
      }
    
    }
    

    2.列表匹配

    def main(args: Array[String]): Unit = {
      val list = List(List(1), List(1, 2), List(1, 2, 3))
    
      for (elem <- list) {
        elem match {
          //1 + 空
          case 1 :: Nil => 1
          //元素x + 元素y + 空
          case x :: y :: Nil => x + "," + y
          //1 + 0个或多个元素,后面的部分赋值给自定义变量
          case 1 :: tail => "以1开头的集合"
          case _ => "default"
        }
      }
    
    }
    

    3.元组匹配

    def main(args: Array[String]): Unit = {
      val tuples = Array((1, 2), (2, 1), (1, 2, 3))
    
      for (elem <- tuples) {
        val res = elem match {
          //匹配以1开头的二元组
          case (1, _) => 1
          //匹配二元组  
          case (x, y) => (y, x)
          case _ => "default"
        }
    
        println(res)
      }
      
    }
    

      由于Map中的元素就是一个一个二元组,所以在遍历时,可以使用元组匹配。

    def main(args: Array[String]): Unit = {
      val map = Map("A" -> 1, "B" -> 2, "C" -> 3)
    
      for ((k, v) <- map) {
        println(k, v)
      }
    
      println("-------------------")
    
      //只匹配v=3的元素
      for ((k, 3) <- map) {
        println(k, 3)
      }
    
      println("-------------------")
    
      //条件守卫。与模式匹配中条件守卫的位置不同。
      for ((k, v) <- map if v > 2) {
        println(k, v)
      }
    
    }
    

      由此可知,在 <- 形式的for循环中,都是在对集合中的元素做模式匹配。

    三、对象匹配

      在对象匹配中,利用对象的unapply方法提取参数,并赋值。

    object MatchObjectDemo {
    
      def main(args: Array[String]): Unit = {
       
        val zs = new Person("zs", 10)
    
        /**
          * 输出结果
          * unapply()...
          * zs
          * 10
          */
        zs match {
          // 1.调用Person的unapply(person: Person),将参数zs传入
          // 2.判断是否返回Some
          // 3.如果返回Some,判断元素个数是否相等(不判断类型)
          // 4.如果元素个数相等,则将Some里的值赋给x和y
          case Person(x, y) =>
            println(x)
            println(y)
          case _ => println("default")
        }
    
      }
    
    }
    
    class Person(_name: String, _age: Int) {
      val name = _name
      val age = _age
    
      override def toString = s"Person($name, $age)"
    }
    
    object Person {
    
      def unapply(person: Person): Option[(String, Int)] = {
        println("unapply()...")
        if (person != null) Some(person.name, person.age) else None
      }
    
    }
    

      case Person(x, y)的写法很具有迷惑性,看起来像是在调用Person的applay方法构建对象,但实际上Person只是标识了去调用哪个类的unapply方法,(x, y)只是两个接收Some元素值的变量,仅此而已。

      与unapply相同作用的还有一个unapplySeq方法,作用与unapply相同,区别在于unapplySeq返回的Some里面的元素是一个集合。

    def unapplySeq(person: Person): Option[Array[Any]] = {
        println("unapplySeq()...")
        if (person != null) Some(Array(person.name, person.age)) else None
    }
    

      

    四、变量声明与模式匹配

      与集合匹配和对象匹配中的格式一致,通过模式匹配,可以快速声明多个变量。

    def main(args: Array[String]): Unit = {
    
      //数组匹配声明变量
      val Array(first, second, _*) = Array(1, 2, 3, 4, 5)
    
      //列表匹配声明变量
      val m :: n :: tail = List(1, 2, 3, 4, 5)
    
      //元组匹配声明变量
      val (x, y, z) = (1, 2, "hello")
    
      // /% 是BigInt中的一个方法,返回一个二元组
      val (q, r) = BigInt(10) /% 3
    
      //对象匹配声明变量。可以这样写,但没必要。
      val Person(name, age) = new Person("zs", 10)
      println(name,age)
      
    }
    

    五、样例类与模式匹配

    Case Class一般被翻译成样例类,它是一种特殊的类,能够被优化以用于模式匹配。
    当一个类被声名为case class的时候,scala会帮助我们做下面几件事情:
    1、构造器中的参数如果不被声明为var的话,它默认的是val类型的,但一般不推荐将构造器中的参数声明为var。
    2、自动创建伴生对象,同时在里面给我们实现子apply方法,使我们在使用的时候可以不直接使用new创建对象。
    3、伴生对象中同样会帮我们实现unapply方法,从而可以将case class应用于模式匹配。
    4、实现自己的toString、hashCode、copy、equals方法
    除此之此,case class与其它普通的scala类没有区别
    object CaseClassDemo {
    
      def main(args: Array[String]): Unit = {
        for (elem <- Array(Dollar(1000.0), Currency(200.0, "rmb"), NoAmount)) {
          val res = elem match {
            case Dollar(v) => v
            case Currency(v, u) => v + u
            case NoAmount =>
            case _ => "default"
          }
    
          println(res)
        }
    
      }
    
    }
    
    abstract class Amount
    
    //样例类的主构造器参数会被当成全局变量 val value
    case class Dollar(value: Double) extends Amount
    
    case class Currency(value: Double, unit: String) extends Amount
    
    case object NoAmount extends Amount
    

    六、最佳实践案例-商品捆绑打折出售

      现在有一些商品,请使用Scala设计相关的样例类,完成商品捆绑打折出售。要求:①商品捆绑可以是单个商品,也可以是多个商品。② 打折时按照折扣x元进行设计.③ 能够统计出所有捆绑商品打折后的最终价格。

      设计样例类:

    abstract class Item
    
    //描述+价格
    case class Book(desc: String, price: Double) extends Item
    
    //描述+折扣+捆绑的其他项
    case class Bundle(desc: String, discount: Double, item: Item*) extends Item
    

      一个捆绑商品的例子

    val bundle = Bundle("书籍", 10, Book("漫画", 40), Bundle("文学作品", 20, Book("阳关", 80), Book("围城", 30)))
    

      知识点1:将desc绑定到第一个book的描述“漫画”

    def main(args: Array[String]): Unit = {
      val bundle = Bundle("书籍", 10, Book("漫画", 40), Bundle("文学作品", 20, Book("阳关", 80), Book("围城", 30)))
    
      val res = bundle match {
        case Bundle(_, _, Book(desc, _), _*) => desc
      }
      println(res)
    
    }
    

      知识点2:通过@表示法将嵌套的值绑定到变量。_*绑定剩余Item到rest

    def main(args: Array[String]): Unit = {
      val bundle = Bundle("书籍", 10, Book("漫画", 40), Bundle("文学作品", 20, Book("阳关", 80), Book("围城", 30)))
    
      val res = bundle match {
        case Bundle(_, _, book@Book(_, _), rest@_*) => (book,rest)
      }
    
      println(res._1) //Book(漫画,40.0)
      println(res._2) //ArraySeq(Bundle(文学作品,20.0,ArraySeq(Book(阳关,80.0), Book(围城,30.0))))
    
    }
    

      最终解答

    object CaseClassDemo {
    
      def main(args: Array[String]): Unit = {
        val bundle = Bundle("书籍", 10, Book("漫画", 40), Bundle("文学作品", 20, Book("阳关", 80), Book("围城", 30)))
    
        val total = price(bundle)
    
        println(total)  //120.0
    
      }
    
      //求捆绑书籍的总价格
      def price(item: Item):Double={
        item match {
          //单本书没有折扣,直接返回价格
          case Book(_,price)=>price
          //捆绑书将捆绑的每一个项的价格分别求出,求和,再减去折扣
          case Bundle(_,discount,items@_*)=>items.map(price).sum-discount
        }
      }
    
    }
    

      

      





  • 相关阅读:
    C风格字符串大写转小写
    指针的引用在函数中的应用
    Debug和Release区别
    差分约束系统(System Of Difference Constraints)
    poj_2299UltraQuickSort && poj_1804Brainman
    计算几何基础——矢量和叉积
    推荐ALGORITHM专题
    后缀数组之倍增法
    静态邻接表的简单实现
    归并排序&&树状数组求逆序数
  • 原文地址:https://www.cnblogs.com/noyouth/p/12767223.html
Copyright © 2011-2022 走看看