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) 密封就是不能在其它文件中定義子類