0.前言
型別檢查和型別轉換在每個語言里面都有對應實作,比如Java 中的instanceof 和 isInstance ,當然Scala語言也有,但是相對于其他語言,Scala 為了簡化開發,產生了強大的模式匹配,其原理和Java中的switch-case很類似,但是其匹配能力更強,不僅僅可以匹配值,匹配型別,也可以進行類匹配,還可以進行前綴類匹配,而且在Spark原始碼中大量使用了模式匹配,另外的就是隱式轉換,在另外一篇文章講解,本文從型別檢查和型別轉換入手,引入Scala常見的幾種模式匹配及其使用,
1.型別檢查
要測驗某個物件是否屬于某個給定的類,可以用isInstanceOf方法,如果測驗成功,可以用asInstanceOf方法進行類
型轉換,
if(p.isInstanceOf[Employee]){
//s的型別轉換為Employee
val s = p.asInstanceOf[Employee]
}
型別轉換主要有下面幾個點要注意的:
-
如果p指向的是
Employee類及其子類的物件,則p.isInstanceOf[Employee]將會成功, -
如果p是null,則
p.isInstanceOf[Employee]將回傳false,且p.asInstanceOf[Employee]將回傳null, -
如果p不是一個
Employee,則p.asInstanceOf[Employee]將拋出例外, -
如果想要測驗p指向的是一個
Employee物件但又不是其子類,可以用:if(p.getClass == classOf[Employee])
classOf方法定義在scala.Predef物件中,因此會被自動引入,不過,與型別檢查和轉換相比,模式匹配通常是更好的選擇,
p match{
//將s作為Employee處理
case s: Employee => ...
//p不是Employee的情況
case _ => ....
}
2.模式匹配
Scala 中的模式匹配總結來說支持下面幾種匹配:值匹配,型別匹配,集合元素,元組匹配,有值或者無值匹配,下面從代碼角度來看看這幾種匹配如何使用,首先模式匹配的語法結構如下:
變數 match {
case xx => 代碼
}
和Java 的不同點,不需要指定break,即有break的效果,使用占位符_ 來代表默認值,另外match 和 if一樣有回傳值,
2.1 值匹配
值匹配,即類似Java 中的整型,字符或者,字串匹配,但是其之處守衛式匹配(可以理解為默認情況下的條件匹配)
//字符匹配
def main(args: Array[String]): Unit = {
val charStr = '6'
charStr match {
case '+' => println("匹配上了加號")
case '-' => println("匹配上了減號")
case '*' => println("匹配上了乘號")
case '/' => println("匹配上了除號")
//注意:不滿足以上所有情況,就執行下面的代碼
case _ => println("都沒有匹配上,我是默認值")
}
}
//字串匹配
def main(args: Array[String]): Unit = {
val arr = Array("hadoop", "zookeeper", "spark")
val name = arr(Random.nextInt(arr.length))
name match {
case "hadoop" => println("大資料分布式存盤和計算框架...")
case "zookeeper" => println("大資料分布式協調服務框架...")
case "spark" => println("大資料分布式記憶體計算框架...")
case _ => println("我不認識你...")
}
}
//守衛式匹配
def main(args: Array[String]): Unit = {
//守衛式
val character = '*'
val num = character match {
case '+' => 1
case '-' => 2
case _ if character.equals('*') => 3
case _ => 4
}
println(character + " " + num)
}
2.2 型別匹配
型別匹配是相對于Java 來說的優勢點,Java是做不到的,匹配格式如下:case 變數名:型別 ,變數名可以用_ 來代替
//型別匹配
def typeMathc (x: Any) = {
x match {
case _: String => println("字串")
case _: Int => println("整形")
case _: Array[Int] => println("正星星陣列")
case _ => println("nothing")
}
}
2.3 匹配陣列,元組,集合
不同于型別匹配的是,型別匹配只能匹配到整個大的型別,而這種匹配可以匹配類似像某類,但是又可以限制匹配類的部分元素
//陣列模式匹配
def arrayMatch(x: Array[Int]) = {
x match {
case Array(1,x,y) => println(x + ":" + y)
case Array(1) => println("only 1 ....")
case Array(1,_*) => println("1 開頭的")
case _ => println("nothing....")
}
}
//list模式匹配
def listMatch() = {
val list = List(3, -1)
//對List串列進行模式匹配,與Array類似,但是需要使用List特有的::運算子
//構造List串列的兩個基本單位是Nil和::,Nil表示為一個空串列
//tail回傳一個除了第一元素之外的其他元素的串列
//分別匹配:帶有指定個數元素的串列、帶有指定元素的串列、以某元素開頭的串列
list match {
case x :: y :: Nil => println(s"x: $x y: $y")
case 0 :: Nil => println("only 0")
case 1 :: _ => println("1 ...")
case _ => println("something else")
}
}
//元組匹配
def tupleMatch() = {
val tuple = (5, 3, 7)
tuple match {
case (1, x, y) => println(s"1, $x, $y")
case (_, z, 5) => println(z)
case _ => println("else")
}
}
當陣列內沒有寫值,下面幾種匹配等效,任意引數等于完全型別匹配
case Array(_*) => println("*")
case _: Array[Int] => println("整個陣列")
2.4 樣例類匹配
case class樣例類是Scala中特殊的類,當宣告樣例類時,以下事情會自動發生:
-
主建構式接收的引數通常不需要顯式使用var或val修飾,Scala會自動使用val修飾
-
自動為樣例類定義了伴生物件,并提供apply方法,不用new關鍵字就能夠構造出相應的物件
-
將生成toString、equals、hashCode和copy方法,除非顯示的給出這些方法的定義
-
繼承了Product和Serializable這兩個特質,也就是說樣例類可序列化和可應用Product的方法
case class是多例的,后面要跟構造引數,case object是單例的,
此外,case class樣例類中可以添加方法和欄位,并且可用于模式匹配,怎么理解樣例類的模式匹配呢,在使用動態系結時候,從樣例類的繼承中可以判斷,某個物件是否屬于某個子類物件,而面向父類的介面,可以簡化編程的設計,跟第一部分說到的isInstanceOf 類似,同時,樣例類可以接受輸入引數進行對應的子類操作,
class Amount
//定義樣例類Dollar,繼承Amount父類
case class Dollar(value: Double) extends Amount
//定義樣例類Currency,繼承Amount父類
case class Currency(value: Double, unit: String) extends Amount
//定義樣例物件Nothing,繼承Amount父類
case object Nothing extends Amount
object CaseClassDemo {
def main(args: Array[String]): Unit = {
judgeIdentity(Dollar(10.0))
judgeIdentity(Currency(20.2,"100"))
judgeIdentity(Nothing)
}
//自定義方法,模式匹配判斷amt型別
def judgeIdentity(amt: Amount): Unit = {
amt match {
case Dollar(value) => println(s"$value")
case Currency(value, unit) => println(s"Oh noes,I got $unit")
case _: Currency => println(s"Oh noes,I go")
case Nothing => println("Oh,GOD!")
}
}
}
2.5 有值無值匹配
Scala Option選項型別用來表示一個值是可選的,有值或無值,
Option[T] 是一個型別為 T 的可選值的容器,可以通過get()函式獲取Option的值,如果值存在,Option[T] 就是一個
Some,如果不存在,Option[T] 就是物件 None ,
Option通常與模式匹配結合使用,用于判斷某個變數是有值還是無值,下面以Map的自帶回傳值Option來看看這種匹配,
val grades = Map("jacky" -> 90, "tom" -> 80, "jarry" -> 95)
def getGrade(name: String): Unit = {
val grade: Option[Int] = grades.get(name)
grade match {
case Some(grade) => println("成績:" + grade)
case None => println("沒有此人成績!")
}
}
def main(args: Array[String]): Unit = {
getGrade("jacky")
getGrade("張三")
}
3. 總結
Scala 中模式匹配,是用來簡化代碼,實作更多強大的不確定或確定的匹配,同時還可以自定義模式匹配,其匹配時候自動利用了apply 和 unapply方法,
吳邪,小三爺,混跡于后臺,大資料,人工智能領域的小菜鳥,
更多請關注

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/237926.html
標籤:其他
