好程序員大數據教程分享Scala系列之模式匹配和樣例類
1.樣例類
在Scala中樣例類是一中特殊的類,樣例類是不可變的,
可以通過值進行比較,可用于模式匹配。
定義一個樣例類:
1.構造器中每一個參數都是val,除非顯示地聲明為var
2.伴生對象提供apply ,讓你不使用new關鍵字就能構造出相應的對象
case class Point(x: Int, y: Int)
創建樣例類對象:
val point = Point(1, 2)
val anotherPoint = Point(1, 2)
val yetAnotherPoint = Point(2, 2)
//訪問對象值
point.x
point.x =1 //不可以
通過值對樣例類對象進行比較:
if (point == anotherPoint) {
println(point + " and " + anotherPoint + " are the same.")
} else {
println(point + " and " + anotherPoint + " are different.")
}
// Point(1,2) 和 Point(1,2)一樣的.
成都創新互聯成立以來不斷整合自身及行業資源、不斷突破觀念以使企業策略得到完善和成熟,建立了一套“以技術為基點,以客戶需求中心、市場為導向”的快速反應體系。對公司的主營項目,如中高端企業網站企劃 / 設計、行業 / 企業門戶設計推廣、行業門戶平臺運營、手機APP定制開發、手機網站開發、微信網站制作、軟件開發、資陽托管服務器等實行標準化操作,讓客戶可以直觀的預知到從成都創新互聯可以獲得的服務效果。
if (point == yetAnotherPoint) {
println(point + " and " + yetAnotherPoint + " are the same.")
} else {
println(point + " and " + yetAnotherPoint + " are different.")
}
// Point(1,2)和Point(2,2)是不同的.
樣例類的拷貝
You can create a (shallow) copy of an instance of a case class simply by using the copy method. You can optionally change the constructor arguments.
case class Message(sender: String, recipient: String, body: String)
val message4 = Message("julien@bretagne.fr", "travis@washington.us", "Me zo o komz gant ma amezeg")
val message5 = message4.copy(sender = message4.recipient, recipient = "claire@bourgogne.fr")
message5.sender // travis@washington.us
message5.recipient // claire@bourgogne.fr
message5.body // "Me zo o komz gant ma amezeg"
在模式匹配中使用樣例類:
abstract class Amount
// 繼承了普通類的兩個樣例類
case class Dollar(value: Double) extends Amount
case class Currency(value: Double, unit: String) extends Amount
case object Nothing extends Amount
object CaseClassDemo {
def main(args: Array[String]): Unit = {
val amt = new Dollar(10);
patternMatch(amt)
}
def patternMatch(amt: Amount) {
amt match {
case Dollar(v) => println("$" + v)
case Currency(_, u) => println("Oh noes, I got " + u)
case Nothing => println("nothing") //樣例對象沒有()
}
}
}
聲明樣例類 ,以下幾件事會自動發生:
1.提供unapply方法,讓模式匹配可以工作
2.生成toString equals hashCode copy 方法,除非顯示給出這些方法的定義。
2.模式匹配
1.更好的switch
Scala中類似Java的switch代碼:
注意:
Scala的模式匹配只會匹配到一個分支,不需要使用break語句,因為它不會掉入到下一個分支。 match是表達式,與if表達式一樣,是有值的:
object PatternDemo {
def main(args: Array[String]): Unit = {
var sign = 0
val ch: Char = 'p'
val valchar = 'p'
var digit = 0
//match 是表達式
ch match {
case '+' => sign = 1
case '-' => sign = -1
//使用|分割多個選項
case '*' | 'x' => sign = 2
//可以使用變量
//如果case關鍵字后面跟著一個變量名,那么匹配的表達式會被賦值給那個變量。
case valchar => sign = 3
//case 類似Java中的default
// 如果沒有模式能匹配,會拋出MacthError
//可以給模式添加守衛
case if Character.isDigit(ch) => digit = Character.digit(ch, 10)
}
println("sign = "+ sign)
}
}
1常量模式(constant patterns) 包含常量變量和常量字面量
scala> val site = "alibaba.com"
scala> site match { case "alibaba.com" => println("ok") }
scala> val ALIBABA="alibaba.com"
//注意這里常量必須以大寫字母開頭
scala> def foo(s:String) { s match { case ALIBABA => println("ok") } }
常量模式和普通的 if 比較兩個對象是否相等(equals) 沒有區別,并沒有感覺到什么威力
2 變量模式(variable patterns)
確切的說單純的變量模式沒有匹配判斷的過程,只是把傳入的對象給起了一個新的變量名。
scala> site match { case whateverName => println(whateverName) }
上面把要匹配的 site對象用 whateverName 變量名代替,所以它總會匹配成功。不過這里有個約定,對于變量,要求必須是以小寫字母開頭,否則會把它對待成一個常量變量,比如上面的whateverName 如果寫成WhateverName就會去找這個WhateverName的變量,如果找到則比較相等性,找不到則出錯。
變量模式通常不會單獨使用,而是在多種模式組合時使用,比如
List(1,2) match{ case List(x,2) => println(x) }
里面的x就是對匹配到的第一個元素用變量x標記。
3 通配符模式(wildcard patterns)
通配符用下劃線表示:"" ,可以理解成一個特殊的變量或占位符。 單純的通配符模式通常在模式匹配的最后一行出現,case => 它可以匹配任何對象,用于處理所有其它匹配不成功的情況。 通配符模式也常和其他模式組合使用:
scala> List(1,2,3) match{ case List(,,3) => println("ok") }
上面的 List(,,3) 里用了2個通配符表示第一個和第二個元素,這2個元素可以是任意類型 通配符通常用于代表所不關心的部分,它不像變量模式可以后續的邏輯中使用這個變量。
4.樣例類匹配
//定義樣例類
abstract class Notification
case class Email(sender: String, title: String, body: String) extends Notification
case class SMS(caller: String, message: String) extends Notification
case class VoiceRecording(contactName: String, link: String) extends Notification
//基于樣例類的模式匹配
def showNotification(notification: Notification): String = {
notification match {
case Email(email, title, ) =>
s"You got an email from $email with title: $title"
case SMS(number, message) =>
s"You got an SMS from $number! Message: $message"
case VoiceRecording(name, link) =>
s"you received a Voice Recording from $name! Click the link to hear it: $link"
}
}
val someSms = SMS("12345", "Are you there?")
val someVoiceRecording = VoiceRecording("Tom", "voicerecording.org/id/123")
println(showNotification(someSms)) //結果:You got an SMS from 12345! Message: Are you there?
println(showNotification(someVoiceRecording)) //結果:you received a Voice Recording from Tom! Click the link to hear it: voicerecording.org/id/123
2.帶守衛的模式
增加布爾表達式或者條件表達式使得匹配更具體。
def showImportantNotification(notification: Notification, importantPeopleInfo: Seq[String]): String = {
notification match {
//僅匹配email在importantPeople列表里的內容
case Email(email, , ) if importantPeopleInfo.contains(email) =>
"You got an email from special someone!"
case SMS(number, ) if importantPeopleInfo.contains(number) =>
"You got an SMS from special someone!"
case other =>
showNotification(other) // nothing special, delegate to our original showNotification function
}
}
val importantPeopleInfo = Seq("867-5309", "jenny@gmail.com")
val someSms = SMS("867-5309", "Are you there?")
val someVoiceRecording = VoiceRecording("Tom", "voicerecording.org/id/123")
val importantEmail = Email("jenny@gmail.com", "Drinks tonight?", "I'm free after 5!")
val importantSms = SMS("867-5309", "I'm here! Where are you?")
println(showImportantNotification(someSms, importantPeopleInfo))
println(showImportantNotification(someVoiceRecording, importantPeopleInfo))
println(showImportantNotification(importantEmail, importantPeopleInfo))
println(showImportantNotification(importantSms, importantPeopleInfo))
5.類型匹配
可以對表達式類型進行匹配:
val arr = Array("hs", 1, 2.0, 'a')
val obj = arr(Random.nextInt(4))
println(obj)
obj match {
case x: Int => println(x)
case s: String => println(s.toUpperCase)
case : Double => println(Int.MaxValue)
case => 0
}
注意: 當你在匹配類型的時候,必須給出一個變量名,否則你將會拿對象本身來進行匹配:
obj match {
case : BigInt => Int.MaxValue // 匹配任何類型為BigInt的對象
case BigInt => -1 // 匹配類型為Class的BigInt對象
}
匹配發生在運行期,Java虛擬機中泛型的類型信息是被擦掉的。因此,你不能用類型來匹配特定的Map類型。
case m: Map[String, Int] => ... // error
// 可以匹配一個通用的映射
case m: Map[, _] => ... // OK
// 但是數組作為特殊情況,它的類型信息是完好的,可以匹配到Array[Int]
case m: Array[Int] => ... // OK
3.匹配數組、列表、元組
數組匹配
val arr1 = Array(1,1)
val res = arr1 match {
case Array(0) => "0"
//匹配包含0的數組
case Array(x, y) => s"$x $y"
// 匹配任何帶有兩個元素的數組,并將元素綁定到x和y
case Array(0, *) => "0..."
//匹配任何以0開始的數組
case => "something else"
}
列表匹配
val lst = List(1,2)
val res2 = list match {
case 0 :: Nil => "0"
case x :: y :: Nil => x + " " + y
case 0 :: tail => "0 ..."
case => "something else"
}
元組匹配
var pair = (1,2)
val res3 = pair match {
case (0, ) => "0 ..."
case (y, 0) => s"$y 0"
case _ => "neither is 0"
}
4.Sealed 類(密封類,備選)
Scala中,Traits 和classes可以被關鍵字sealed修飾, 修飾,被該關鍵字修飾后,它所有的子類都必須在同一文件中被定義。
這樣做的好處是:當你用樣例類來做模式匹配時,你可以讓編譯器確保你已經列出了所有可能的選擇,編譯器可以檢查模式語句的完整性。
sealed abstract class Furniture
case class Couch() extends Furniture
case class Chair() extends Furniture
//此時無需定義能匹配所有的類型了
def findPlaceToSit(piece: Furniture): String = piece match {
case a: Couch => "Lie on the couch"
case b: Chair => "Sit on the chair"
}
當前文章:好程序員大數據教程分享Scala系列之模式匹配和樣例類
標題路徑:http://newbst.com/article46/jocdhg.html
成都網站建設公司_創新互聯,為您提供網站制作、網頁設計公司、定制開發、自適應網站、建站公司、虛擬主機
聲明:本網站發布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創新互聯