2018年第46周-scala入門-模式匹配

黃小數發表於2019-02-16

模式匹配是scala中非常有特色, 非常強大的一種工. 模式匹配, 其實類似於java的switch語法, 即對一個值進行判斷, 然後針對不同的條件, 進行不同的處理.
但是scala的模式匹配的功能比java的switch語法的功能強很多, java的只能對值進行匹配, 還是隻能int和列舉的值進行匹配. 但是scala的模式匹配除了可以對值進行匹配外, 還可以有以下匹配:

  1. 對型別進行匹配
  2. 對Array和List的元素情況進行匹配
  3. 對case class進行匹配
  4. 有值或沒值(Option)進行匹配.

簡單例子

scala是沒有java的switch語法, 但提供更強大的match語法, 即模式匹配.
match語法如下: 變數名 match{case 值 => 表示式}
如果值為下劃線, 則表示不滿足以上所有情況的預設情況處理.
match語法中, 只要一個case分支滿足, 則不會繼續判斷下一個case分支. 這一點跟java不一樣, 也避免了忘記寫break造成的bug.

例子: 成績評價

def judgeGrade(grade: String){
   grade match{
       case "A" => println("Excellent")
       case "B" => println("Good")
       case "C" => println("Just so so")
       case _ => println("you need work harder")
   }
}

在模式匹配中使用if守衛

scala的模式匹配語法, 有一個特點在於, 可以在case後的條件判斷中, 不僅僅只是提供一個值, 而是可以在值後面再加一個if守衛, 進行雙重過濾.
例子: 成績評價(升級版, 可根據名稱給出不同的提示)

def judgeGrade(name:String, grade:String){
  grade match{
    case "A" => println(name+", you are excellent")
    case "B" => println(name+", you are good")
    case "C" if name == "jc" => println(name+", you are a good boy, come on")
    case "C" => println(name+", you are just so so") //這句必須是在上一句的後面, 不然就永遠匹配不到jc
    case _ => println("you need to work harder")
  }
}

在模式匹配中進行變數賦值

scala的模式匹配語法, 可以將模式匹配的預設情況, 下劃線, 替換為一個變數名, 此時模式匹配語法就會將要匹配的值賦值給這個變數, 從而可以在後面的處理語句中使用被匹配的值.
例子: 成績評價(升級版, 可根據名稱給出不同的提示, 並且帶成績)

def judgeGrade(name:String, grade:String){
  grade match{
    case "A" => println(name+", you are excellent")
    case "B" => println(name+", you are good")
    case "C" => println(name+", you are just so so")
    case _actualGrade if name == "jc" => println(name+", you are a good boy, come on, your grade is "+_actualGrade)
    case _actualGrade => println("you need to work harder, your grade is"+_actualGrade)
  }
}

對型別進行模式匹配

scala的模式匹配其中一個強大功能就是, 可以直接匹配型別.

例子: 異常處理

import java.io_
def processException(){
  e match{
     case e1: IllegalArgumentException=> println("that has illegal arguments! exception is: "+e1)
     case e2: FileNotFoundException=> println("can not find the file! exception is: "+e2)  
     case e3: IOException=> println("you got an IOException")
     case _: Exception=>println("I have not idea what exception is")
  }
}

注意這裡要與上面的”模式匹配對值的匹配”進行對比, 知道它們的差異, 匹配值是 case 值=> 表示式, 而匹配型別是case 變數: 型別=>表示式. 所以匹配型別預設就可以進行變數賦值. 而匹配值則需要以下劃線來定義新的變數來賦值.

對Array和List進行模式匹配

對Array進行模式匹配, 分別可以匹配帶有指定元素的陣列, 帶有指定元素個數的陣列, 指定以某個元素打頭的陣列
對List進行模式匹配, 跟Array類似, 但是需要List特有的::操作符

例子: 對朋友打招呼

def greeting(peoples: Array[String]){
  peoples match{
     case Array("jc")=> println("Hi, jc!")
     case Array(girl1, girl2, girl3)=> println("Hi, girls, nice to meet you. "+girl1+" and "+girl2+" and "+ girl3) 
     case Array("jc",_*)=> println("Hi, jc, please introduce your friends to me.")
     case _=> println("hey guys, who are you!")
  }
}

var a = Array("jc")
greeting(a)
a = Array("jc","jay","jack")
greeting(a)
a = Array("jc","jay","jack","john")
greeting(a)
a = Array("jay","jack","john","johnny")
greeting(a)


def greeting(peoples: List[String]){
  peoples match{
     case "jc"::Nil=> println("Hi, jc!")
     case girl1::girl2::girl3::Nil=> println("Hi, girls, nice to meet you. "+girl1+" and "+girl2+" and "+girl3) 
     case "jc"::tail=> println("Hi, jc, please introduce your friends to me.")
     case _=> println("hey guys, who are you!")
  }
}


var a = List("jc")
greeting(a)
a = List("jc","jay","jack")
greeting(a)
a = List("jc","jay","jack","john")
greeting(a)
a = List("jay","jack","john","johnny")
greeting(a)

上面兩個功能都一樣, case語句分別是一下功能: 只有jc元素的, 3個元素的集合, jc元素的打頭的, 其他情況的.

case class與模式匹配

scala提供了一種特殊的累, 就是用case class的類, 這種類稱為樣例類. 樣例類其實有點類似於嚴格定義的JavaBean, 只定義了field, 並且由scala編譯時自動提供getter和setter方法, 但是沒有其他方法.
除此之外,scala會自動為樣例類定義伴生物件, 也就是object, 並且定義了apply方法, 該apply方法的引數跟主建構函式的引數一樣, 病返回樣例類.
簡單的說, 樣例類簡化了定義類和例項化類的語法.

例子: 學校廣播

class Person
case class Teacher(name:String, subject:String) extends Person
case class Student(name:String, classroom:String) extends Person

def broadcast(p: Person){
  p match{
   case Teacher(name, subject)=> println("教"+subject+"的"+name+"老師馬上到教導處來")
   case Student(name, classroom)=> println(classroom+name+"馬上到教導處來")
   case _=>println("三年二班")
  }
}

val t = Teacher("周杰倫","音樂")
val s = Student("周杰倫","三二班")
broadcast(t)
broadcast(s)

Option與模式匹配

scala有一種特殊的型別叫Option, Option有兩個值, 一種是Some, 代表有值, 一種是None代表沒有值.

Option通常會用於模式匹配中, 用於判斷某個變數是否有值還是沒有值, 這比null來的更加語義化.
例子: 成績查詢

val  grades = Map("jc"->"A","jay"->"B","jack"->"M")
def getGrade(name:String){
   var grade = grades.get(name)
   grade match{
     case Some(grade)=> println("Hi "+name+", your grade is "+grade)
     case None=> println("Sorry "+name+", your grade is not in the system.")
   }
}  
getGrade("jc")
getGrade("jay")
getGrade("jack")
getGrade("john")

相關文章