好程序員大數(shù)據(jù)教程分享Scala系列之模式匹配和樣例類
1.樣例類
在Scala中樣例類是一中特殊的類,樣例類是不可變的,
可以通過值進(jìn)行比較,可用于模式匹配。
定義一個樣例類:
1.構(gòu)造器中每一個參數(shù)都是val,除非顯示地聲明為var
2.伴生對象提供apply ,讓你不使用new關(guān)鍵字就能構(gòu)造出相應(yīng)的對象
case class Point(x: Int, y: Int)
創(chuàng)建樣例類對象:
val point = Point(1, 2)
val anotherPoint = Point(1, 2)
val yetAnotherPoint = Point(2, 2)
//訪問對象值
point.x
point.x =1 //不可以
通過值對樣例類對象進(jìn)行比較:
if (point == anotherPoint) {
println(point + " and " + anotherPoint + " are the same.")
} else {
println(point + " and " + anotherPoint + " are different.")
}
// Point(1,2) 和 Point(1,2)一樣的.
成都創(chuàng)新互聯(lián)成立以來不斷整合自身及行業(yè)資源、不斷突破觀念以使企業(yè)策略得到完善和成熟,建立了一套“以技術(shù)為基點(diǎn),以客戶需求中心、市場為導(dǎo)向”的快速反應(yīng)體系。對公司的主營項(xiàng)目,如中高端企業(yè)網(wǎng)站企劃 / 設(shè)計(jì)、行業(yè) / 企業(yè)門戶設(shè)計(jì)推廣、行業(yè)門戶平臺運(yùn)營、手機(jī)APP定制開發(fā)、手機(jī)網(wǎng)站開發(fā)、微信網(wǎng)站制作、軟件開發(fā)、資陽托管服務(wù)器等實(shí)行標(biāo)準(zhǔn)化操作,讓客戶可以直觀的預(yù)知到從成都創(chuàng)新互聯(lián)可以獲得的服務(wù)效果。
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") //樣例對象沒有()
}
}
}
聲明樣例類 ,以下幾件事會自動發(fā)生:
1.提供unapply方法,讓模式匹配可以工作
2.生成toString equals hashCode copy 方法,除非顯示給出這些方法的定義。
2.模式匹配
1.更好的switch
Scala中類似Java的switch代碼:
注意:
Scala的模式匹配只會匹配到一個分支,不需要使用break語句,因?yàn)樗粫羧氲较乱粋€分支。 match是表達(dá)式,與if表達(dá)式一樣,是有值的:
object PatternDemo {
def main(args: Array[String]): Unit = {
var sign = 0
val ch: Char = 'p'
val valchar = 'p'
var digit = 0
//match 是表達(dá)式
ch match {
case '+' => sign = 1
case '-' => sign = -1
//使用|分割多個選項(xiàng)
case '*' | 'x' => sign = 2
//可以使用變量
//如果case關(guān)鍵字后面跟著一個變量名,那么匹配的表達(dá)式會被賦值給那個變量。
case valchar => sign = 3
//case 類似Java中的default
// 如果沒有模式能匹配,會拋出MacthError
//可以給模式添加守衛(wèi)
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) 沒有區(qū)別,并沒有感覺到什么威力
2 變量模式(variable patterns)
確切的說單純的變量模式?jīng)]有匹配判斷的過程,只是把傳入的對象給起了一個新的變量名。
scala> site match { case whateverName => println(whateverName) }
上面把要匹配的 site對象用 whateverName 變量名代替,所以它總會匹配成功。不過這里有個約定,對于變量,要求必須是以小寫字母開頭,否則會把它對待成一個常量變量,比如上面的whateverName 如果寫成WhateverName就會去找這個WhateverName的變量,如果找到則比較相等性,找不到則出錯。
變量模式通常不會單獨(dú)使用,而是在多種模式組合時(shí)使用,比如
List(1,2) match{ case List(x,2) => println(x) }
里面的x就是對匹配到的第一個元素用變量x標(biāo)記。
3 通配符模式(wildcard patterns)
通配符用下劃線表示:"" ,可以理解成一個特殊的變量或占位符。 單純的通配符模式通常在模式匹配的最后一行出現(xiàn),case => 它可以匹配任何對象,用于處理所有其它匹配不成功的情況。 通配符模式也常和其他模式組合使用:
scala> List(1,2,3) match{ case List(,,3) => println("ok") }
上面的 List(,,3) 里用了2個通配符表示第一個和第二個元素,這2個元素可以是任意類型 通配符通常用于代表所不關(guān)心的部分,它不像變量模式可以后續(xù)的邏輯中使用這個變量。
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)) //結(jié)果:You got an SMS from 12345! Message: Are you there?
println(showNotification(someVoiceRecording)) //結(jié)果:you received a Voice Recording from Tom! Click the link to hear it: voicerecording.org/id/123
2.帶守衛(wèi)的模式
增加布爾表達(dá)式或者條件表達(dá)式使得匹配更具體。
def showImportantNotification(notification: Notification, importantPeopleInfo: Seq[String]): String = {
notification match {
//僅匹配email在importantPeople列表里的內(nèi)容
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.類型匹配
可以對表達(dá)式類型進(jìn)行匹配:
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
}
注意: 當(dāng)你在匹配類型的時(shí)候,必須給出一個變量名,否則你將會拿對象本身來進(jìn)行匹配:
obj match {
case : BigInt => Int.MaxValue // 匹配任何類型為BigInt的對象
case BigInt => -1 // 匹配類型為Class的BigInt對象
}
匹配發(fā)生在運(yùn)行期,Java虛擬機(jī)中泛型的類型信息是被擦掉的。因此,你不能用類型來匹配特定的Map類型。
case m: Map[String, Int] => ... // error
// 可以匹配一個通用的映射
case m: Map[, _] => ... // OK
// 但是數(shù)組作為特殊情況,它的類型信息是完好的,可以匹配到Array[Int]
case m: Array[Int] => ... // OK
3.匹配數(shù)組、列表、元組
數(shù)組匹配
val arr1 = Array(1,1)
val res = arr1 match {
case Array(0) => "0"
//匹配包含0的數(shù)組
case Array(x, y) => s"$x $y"
// 匹配任何帶有兩個元素的數(shù)組,并將元素綁定到x和y
case Array(0, *) => "0..."
//匹配任何以0開始的數(shù)組
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可以被關(guān)鍵字sealed修飾, 修飾,被該關(guān)鍵字修飾后,它所有的子類都必須在同一文件中被定義。
這樣做的好處是:當(dāng)你用樣例類來做模式匹配時(shí),你可以讓編譯器確保你已經(jīng)列出了所有可能的選擇,編譯器可以檢查模式語句的完整性。
sealed abstract class Furniture
case class Couch() extends Furniture
case class Chair() extends Furniture
//此時(shí)無需定義能匹配所有的類型了
def findPlaceToSit(piece: Furniture): String = piece match {
case a: Couch => "Lie on the couch"
case b: Chair => "Sit on the chair"
}
當(dāng)前文章:好程序員大數(shù)據(jù)教程分享Scala系列之模式匹配和樣例類
標(biāo)題路徑:http://redsoil1982.com.cn/article46/jocdhg.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站制作、網(wǎng)頁設(shè)計(jì)公司、定制開發(fā)、自適應(yīng)網(wǎng)站、建站公司、虛擬主機(jī)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)