12. Scala模式匹配

来源:https://www.cnblogs.com/zhanghuicheng/archive/2019/05/17/10867153.html
-Advertisement-
Play Games

12.1 match 12.1.1 基本介紹 Scala中的模式匹配類似於Java中的switch語法,但是更加強大 模式匹配語法中,採用match關鍵字聲明,每個分支採用case關鍵字進行聲明,當需要匹配時,會從第一個case分支開始,如果匹配成功,那麼執行對應的邏輯代碼,如果匹配不成功,繼續執行 ...


12.1 match 

  12.1.1 基本介紹 

      Scala中的模式匹配類似於Java中的switch語法,但是更加強大

      模式匹配語法中,採用match關鍵字聲明,每個分支採用case關鍵字進行聲明,當需要匹配時,會從第一個case分支開始,如果匹配成功,那麼執行對應的邏輯代碼,如果匹配不成功,繼續執行下一個分支進行判斷。如果所有的case都不匹配,那麼會執行case_分支,類似於Java中的default語句

  12.1.2 scala的match的快速入門案例 

object boke_demo01 {

  def main(args: Array[String]): Unit = {
    val oper = '+'
    val n1 = 20
    val n2 = 10
    var res = 0
    //說明
    //1. match (類似java switch) 和  case 是關鍵字
    //2. 如果匹配成功, 則 執行 => 後面的代碼塊.
    //3. 匹配的順序是從上到下,匹配到一個就執行對應的 代碼
    //4. => 後面的代碼塊 不要寫 break ,會自動的退出match
    //5. 如果一個都沒有匹配到,則執行 case _ 後面的代碼塊
    oper match {
      case '+' => {
        res = n1 + n2
        println("ok~~")
        println("hello~~")
      }
      case '-' => res = n1 - n2
      case '*' => res = n1 * n2
      case '/' => res = n1 / n2
      case 1 => println("匹配到1")
      case 1.1 => println("匹配1.1")
      case _ => println("oper error")
    }
    println("res=" + res)

  }
}

  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 應用案例  

object boke_demo01 {

  def main(args: Array[String]): Unit = {

    for (ch <- "+-3!") { //是對"+-3!" 遍歷
      var sign = 0
      var digit = 0
      ch match {
        case '+' => sign = 1
        case '-' => sign = -1
        // 說明..
        // 如果 case 後有 條件守衛即if ,那麼這時的 _ 不是表示預設匹配
        // 表示忽略 傳入 的 ch
        case _ if ch.toString.equals("3") => digit = 3
        case _ => sign = 2
      }
      //分析
      // + 1 0
      // - -1 0
      // 3 0 3
      // ! 2 0
      println(ch + " " + sign + " " + digit)
    }

  }
}

12.3 模式中的變數 

  12.3.1 基本介紹  

      如果在case關鍵字後跟變數名,那麼match前表達式的值會賦給那個變數

  12.3.2 應用案例 

object boke_demo01 {

  def main(args: Array[String]): Unit = {
    val ch = 'U'
    ch match {
      case '+' => println("ok~")
      // 下麵 case mychar 含義是 mychar = ch
      case mychar => println("ok~" + mychar)
      case _ => println("ok~~")
    }

    val ch1 = '+'
    //match是一個表達式,因此可以有返回值
    //返回值就是匹配到的代碼塊的最後一句話的值
    val res = ch1 match {
      case '+' => ch1 + " hello "
      case _ => println("ok~~")
    }

    println("res=" + res)
  }
}

12.4 類型匹配 

  12.4.1 基本介紹 

      可以匹配對象的任意類型,這樣做避免了使用isInstanceOf和asInstanceOf

  12.4.2 應用案例 

object boke_demo01 {

  def main(args: Array[String]): Unit = {
    val a = 8
    //說明 obj 實例的類型 根據 a 的值來返回
    val obj = if (a == 1) 1
    else if (a == 2) "2"
    else if (a == 3) BigInt(3)
    else if (a == 4) Map("aa" -> 1)
    else if (a == 5) Map(1 -> "aa")
    else if (a == 6) Array(1, 2, 3)
    else if (a == 7) Array("aa", 1)
    else if (a == 8) Array("aa")

    //說明
    //1. 根據  obj 的類型來匹配
    // 返回值
    val result = obj match {

      case a: Int => a
      case b: Map[String, Int] => "對象是一個字元串-數字的Map集合"
      case c: Map[Int, String] => "對象是一個數字-字元串的Map集合"
      case d: Array[String] => d //"對象是一個字元串數組"
      case e: Array[Int] => "對象是一個數字數組"
      case f: BigInt => Int.MaxValue
      case y: Float => println("xx")
      case _ => "啥也不是"
    }

    println(result)

  }
}

  12.4.3 類型匹配註意事項 

      1) Map[String, Int]和Map[Int, String]是兩種不同的類型,其它類推

      2) 在進行類型匹配時,編譯器會預先檢測是否有可能的匹配,如果沒有則報錯

object boke_demo01 {

  def main(args: Array[String]): Unit = {

    val obj = 10
    val result = obj match {
      case a: Int => a
      //case b: Map[String, Int] => "Map集合"    //取消註釋之後會報錯
      case _ => "啥也不是"
    }

  }
}

      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 應用案例 

import scala.collection.mutable.ArrayBuffer

object boke_demo01 {

  def main(args: Array[String]): Unit = {

    //    val arrs = Array(Array(0), Array(1, 0), Array(0, 1, 0),
    //      Array(1, 1, 0), Array(1, 1, 0, 1))
    //
    //    for (arr <- arrs ) {
    //      val result = arr match {
    //        case Array(0) => "0"
    //        case Array(x, y) => x + "=" + y
    //        case Array(0, _*) => "以0開頭和數組"
    //        case _ => "什麼集合都不是"
    //      }
    //      // result = 0
    //      // result = 1 = 0
    //      // result = 以0開頭和數組
    //      // result = 什麼集合都不是
    //      // result = 什麼集合都不是
    //      println("result = " + result)
    //    }

    //給你一個數組集合,如果該數組是  Array(10,20) , 請使用預設匹配,返回Array(20,10)


    val arrs2 = Array(Array(0), Array(1, 0), Array(0, 1, 0),
      Array(1, 1, 0), Array(1, 1, 0, 1))

    for (arr <- arrs2) {
      val result = arr match {
        //case Array(0) => "0"
        case Array(x, y) => ArrayBuffer(y, x) //Array(y,x).toBuffer //? ArrayB(y,x)
        //case Array(0, _*) => "以0開頭和數組"
        case _ => "不處理~~"
      }

      println("res=" + result) //ArrayBuffer(0,1)
    }

  }
}

12.6 匹配列表 

      -案例演示

object boke_demo01 {

  def main(args: Array[String]): Unit = {

    for (list <- Array(List(0), List(1, 0), List(0, 0, 0), List(1, 0, 0))) {
      val result = list match {
        case 0 :: Nil => "0" //
        case x :: y :: Nil => x + " " + y //
        case 0 :: tail => "0 ..." //
        case x :: Nil => x
        case _ => "something else"
      }
      //1. 0
      //2. 1 0
      //3. 0 ...
      //4. something else
      println(result)
    }

  }
}

12.7 匹配元組 

      -案例演示

object boke_demo01 {

  def main(args: Array[String]): Unit = {
    //如果要匹配 (10, 30) 這樣任意兩個元素的對偶元組,應該如何寫
    for (pair <- Array((0, 1), (1, 0), (10, 30), (1, 1), (1, 0, 2))) {
      val result = pair match { //
        case (0, _) => "0 ..." //
        case (y, 0) => y //
        case (x, y) => (y, x) //"匹配到(x,y)" + x + " " + y
        case _ => "other" //.
      }
      //1. 0 ...
      //2. 1
      //3. (30,10)
      //4. (1,1)
      //5. other
      println(result)
    }

  }
}

12.8 對象匹配 

  12.8.1 基本介紹 

      對象匹配,什麼才算是匹配呢?規則如下:

        1) case中對象的unapply方法(對象提取器)返回Some集合則為匹配成功

        2) 返回None集合則為匹配失敗

  12.8.2 快速入門 

object boke_demo01 {

  def main(args: Array[String]): Unit = {

    // 模式匹配使用:
    val number: Double = Square(6.0) // 36.0 //

    number match {
      //說明 case Square(n) 的運行的機制
      //1. 當匹配到 case Square(n)
      //2. 調用Square 的 unapply(z: Double),z 的值就是 number
      //3. 如果對象提取器 unapply(z: Double) 返回的是Some(6) ,則表示匹配成功,同時
      //   將6 賦給 Square(n) 的n
      //4.  果對象提取器 unapply(z: Double) 返回的是None ,則表示匹配不成功
      case Square(n) => println("匹配成功 n=" + n)
      case _ => println("nothing matched")
    }


  }
}

//說明

object Square {
  //說明
  //1. unapply方法是對象提取器
  //2. 接收z:Double 類型
  //3. 返回類型是Option[Double]
  //4. 返回的值是 Some(math.sqrt(z)) 返回z的開平方的值,並放入到Some(x)
  def unapply(z: Double): Option[Double] = {
    println("unapply被調用 z 是=" + z)
    Some(math.sqrt(z))
    //None
  }

  def apply(z: Double): Double = z * z
}

  12.8.3 應用案例2 

      -案例演示

object boke_demo01 {

  def main(args: Array[String]): Unit = {

    val namesString = "Alice,Tom,Jack" //字元串
    //說明
    namesString match {
      // 當 執行   case Names(first, second, third)
      // 1. 會調用 unapplySeq(str),把 "Alice,Tom,Jack" 傳入給 str
      // 2. 如果 返回的是 Some("Alice","Tom","Jack"),分別給 (first, second, third)
      //    註意,這裡的返回的值的個數需要和 (first, second, third)要一樣
      // 3. 如果返回的None ,表示匹配失敗

      case Names(first, second, third) => {
        println("the string contains three people's names")
        // 列印字元串
        println(s"$first $second $third")
      }
      case _ => println("nothing matched")
    }

  }
}

//object
object Names {
  //當構造器是多個參數時,就會觸發這個對象提取器
  def unapplySeq(str: String): Option[Seq[String]] = {
    if (str.contains(",")) Some(str.split(","))
    else None
  }
}

      -案例演示小結

        1) 當case後面的對象提取器方法的參數為多個,則會預設調用def unapplySeq()方法

        2) 如果unapplySeq返回的是Some,獲取其中的值,判斷得到的sequence中的元素的個數是否是三個,如果是三個,則把三個元素分別取出,賦值給first,second和third

        3) 其它的規則不變

12.9 變數聲明中的模式  

  12.9.1 基本介紹 

      match中每一個case都可以單獨取出來,意思是一樣的

  12.9.2 應用案例 

object boke_demo01 {

  def main(args: Array[String]): Unit = {

    val (x, y, z) = (1, 2, "hello")
    println("x=" + x)
    val (q, r) = BigInt(10) /% 3 //說明  q = BigInt(10) / 3 r = BigInt(10) % 3
    val arr = Array(1, 7, 2, 9)
    val Array(first, second, _*) = arr // 提出arr的前兩個元素
    println(first, second)

  }
}

12.10 for表達式中的模式 

  12.10.1 基本介紹 

      for迴圈也可以進行模式匹配

  12.10.2 應用案例 

object boke_demo01 {

  def main(args: Array[String]): Unit = {
    val map = Map("A" -> 1, "B" -> 0, "C" -> 3)
    for ((k, v) <- map) {
      println(k + " -> " + v) // 出來三個key-value ("A"->1), ("B"->0), ("C"->3)
    }
    //說明 : 只遍歷出 value =0 的key-value ,其它的過濾掉
    println("--------------(k, 0) <- map-------------------")
    for ((k, 0) <- map) {
      println(k + " --> " + 0)
    }

    //說明, 這個就是上面代碼的另外寫法, 只是下麵的用法靈活和強大
    println("--------------(k, v) <- map if v == 0-------------------")
    for ((k, v) <- map if v >= 1) {
      println(k + " ---> " + v)
    }

  }
}

12.11 樣例(模版)類 

  12.11.1 樣例類快速入門 

object CaseClassDemo01 {
  def main(args: Array[String]): Unit = {
      println("hello~~")
  }
}

abstract class Amount
case class Dollar(value: Double) extends Amount    //樣例類
case class Currency(value: Double, unit: String) extends Amount //樣例類
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 

      -案例演示

object boke_demo01 {

  def main(args: Array[String]): Unit = {
    //該案例的作用就是體驗使用樣例類方式進行對象匹配簡潔性
    for (amt <- Array(Dollar(1000.0), Currency(1000.0, "RMB"), NoAmount)) {
      val result = amt match {
        //說明
        case Dollar(v) => "$" + v // $1000.0
        //說明
        case Currency(v, u) => v + " " + u // 1000.0 RMB
        case NoAmount => "NoAmount" // NoAmount
      }
      println(amt + ": " + result)
    }

  }
}

abstract class Amount

case class Dollar(value: Double) extends Amount //樣例類
case class Currency(value: Double, unit: String) extends Amount //樣例類
case object NoAmount extends Amount //樣例類

  12.11.4 應用案例2 

      -說明

        樣例類的copy方法和帶名參數

        copy創建一個與現有對象值相同的新對象,並可以通過帶名參數來修改某些屬性

      -案例演示

object boke_demo01 {

  def main(args: Array[String]): Unit = {
    val amt = new Currency(3000.0, "RMB")
    val amt2 = amt.copy() // 克隆,創建的對象和amt的屬性一樣
    println("amt2.value" + amt2.value + " amt2.unit= " + amt2.unit)
    println(amt2)

    val amt3 = amt.copy(value = 8000.0)
    println(amt3)

    val amt4 = amt.copy(unit = "美元")
    println(amt4)
  }
}


abstract class Amount

case class Dollar(value: Double) extends Amount //樣例類
case class Currency(value: Double, unit: String) extends Amount //樣例類
case object NoAmount extends Amount //樣例類

12.12 case語句的中置(綴)表達式 

  12.12.1 基本介紹 

      什麼是中置表達式?1 + 2,這就是一個中置表達式。如果unapply方法產出一個元組,可以在case語句中使用中置表示法。比如可以匹配一個List序列

  12.12.2 應用案例 

      -案例演示

object boke_demo01 {

  def main(args: Array[String]): Unit = {
    List(1, 3, 5, 9) match { //修改並測試
      //1.兩個元素間::叫中置表達式,至少first,second兩個匹配才行.
      //2.first 匹配第一個 second 匹配第二個, rest 匹配剩餘部分(5,9)
      case first :: second :: rest => println(first + " " + second + " " + rest.length + " " + rest) //
      case _ => println("匹配不到...")
    }

  }
}

12.13 密封類 

  12.13.1 基本介紹 

      1) 如果想讓case類的所有子類都必須在申明該類的相同的源文件中定義,可以將樣例類的通用超類聲明為sealed,這個超類稱之為密封類

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

      

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一位不編程的分析師的專業生命周期是不會長的,一位不做實驗的設計思維研究者是不會有太多創意的,一位只讀書不思考的讀者是不會有太多深度汲取。設計思維源於IDEO的提出,它是一個概念,更是一種實踐。 一、 發明總結——思維的躍越 《設計改變一切》作者為蒂姆.布朗,創辦的IDEO公司直接參与了世界上第一臺鼠 ...
  • saltstack配置管理 Saltstack狀態模塊 遠程執行模塊的執行是過程式,而狀態是對minion的一種描述和定義,管理人員不需要關係部署任務如何完成的,只需要描述minion的狀態描述。它的和興是寫sls(Salt State file)文件,sls文件預設格式為YAML格式,並預設使用j ...
  • `起因:`最近在做統計計算,創建的實體中屬性比較多,都是一些數值,一開始是通過get、set方法進行賦值,占用了很多業務代碼方法的長度,可讀性不太好,後來改用了添加構造器的方式,稍顯精簡了一點,但是每次賦值的時候都都必須註意是不是對應上了。最後決定改用Bulider模式,確實好用很多。 下麵通過一個 ...
  • 上節課複習 1. 什麼是編程語言:編程語言是人與電腦溝通的介質 2. 什麼是編程:編程是使用編程語言編寫一大堆的文件 3. 為什麼要編程:奴役電腦,解放勞動力 4. 電腦五大組成部分 1. CPU 1. 控制器:控制硬體 2. 運算器:邏輯運算和算術運算 2. 記憶體: 1. 優點:速度快 2. ...
  • Spring Boot項目中數據源的配置可以通過兩種方式實現: 1.application.yml或者application.properties配置 2.註入DataSource及SqlSessionFactory兩個Bean 通過第二種方式配置數據源則按照MybatisPlus官方文檔使用分頁及 ...
  • 定義 function 函數名(形參列表){} 調用 函數名(實參列表); 參數預設值 預設值參數需放在形參列表最後連續排列 傳參方式 值傳遞:函數內外是兩個獨立的值。 引用傳遞(&):函數內外是同一個值。 返回值 return 退出函數,返回到調用函數的地方向後執行,也可以返回數據。 如需在函數內 ...
  • 最近項目需要用到類似access token進行加解密、驗簽的需求,本人在此做個小筆記記錄一下,以供他人參考。 一共會用到2中加解密,HS256 和 RS256,本文只是對 HS256做個備註,好了直接上代碼,先引入jar包 <dependency> <groupId>io.jsonwebtoken ...
  • API概述 什麼叫做API? API(Application Programming lnterface),應用程式編程介面。 所謂API就是值好多的類,好多的方法,JDK給我們提供了很多現成的類,我們可以直接去使用,這些類就是API "API官方文檔" 常見的幾個API之Scanner類的使用 1 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...