1. 模式匹配
1.1. 更好的 Switch
Scala 中類似 Java 的 switch 代碼:
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 valchar => sign = 3 //case _ 類似Java中的default // 如果沒有模式能匹配,會拋出MacthError //可以給模式添加守衛 case _ if Character.isDigit(ch) => digit = Character.digit(ch, 10) } println("sign = "+ sign) } }
1.2. 樣例類匹配
//定義樣例類abstract class Notificationcase class Email(sender: String, title: String, body: String) extends Notificationcase class SMS(caller: String, message: String) extends Notificationcase 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
1.3. 帶守衛的模式
增加布爾表達式使得匹配更具體。
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", "[email protected]")val someSms = SMS("867-5309", "Are you there?") val someVoiceRecording = VoiceRecording("Tom", "voicerecording.org/id/123") val importantEmail = Email("[email protected]", "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))
1.4. 類型匹配
val arr = Array("hello", 1, 2.0, 'a') val obj = arr(Random.nextInt(4)) obj match { case x: Int => x case s: String => Integer.parseInt(s) case _: BigInt => Int.MaxValue case _ => 0}
1.5. 匹配數組、列表、元組
數組匹配
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"}
2. Sealed 類 (密封類)
Scala 中,Traits 和 class 可以被關鍵字 Sealed 修飾,被該關鍵字修飾後,它所有的子類都必須在同一文件中被定義。
sealed abstract class Furniturecase class Couch() extends Furniturecase 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"}
3. 樣例類
在 Scala 中樣例類是一中特殊的類,樣例類是不可變的,可以通過值進行比較,可用於模式匹配。
定義一個樣例類:
case class Point(x: Int, y: Int)
創建樣例類對象:
val point = Point(1, 2) val anotherPoint = Point(1, 2) val yetAnotherPoint = Point(2, 2)
通過值對樣例類對象進行比較:
if (point == anotherPoint) { println(point + " and " + anotherPoint + " are the same.") } else { println(point + " and " + anotherPoint + " are different.") }// Point(1,2) 和 Point(1,2)一樣的.if (point == yetAnotherPoint) { println(point + " and " + yetAnotherPoint + " are the same.") } else { println(point + " and " + yetAnotherPoint + " are different.") }// Point(1,2)和Point(2,2)是不同的.
在模式匹配中使用樣例類:
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) 構造器中每一個參數都是 val,除非顯示地聲明爲 var
(2) 伴生對象提供 apply ,讓你不使用 new 關鍵字就能構造出相應的對象
(3) 提供 unapply 方法,讓模式匹配可以工作
(4) 生成 toString,equals,hashCode,copy 方法,除非顯示給出這些方法的定義。
4. Option 類型
在 Scala 中 Option 類型樣例類用來表示可能存在或也可能不存在的值( Option 的子類有 Some 和 None )。Some 包裝了某個值,None 表示沒有值。
object OptionDemo { def main(args: Array[String]) { val map = Map("a" -> 1, "b" -> 2) val v = map.get("b") match { case Some(i) => i case None => 0 } println(v) //更好的方式 val v1 = map.getOrElse("c", 0) println(v1) } }
5. 偏函數
被包在花括號內沒有 match 的一組 case 語句是一個偏函數,它是 PartialFunction[A, B] 的一個實例,A 代表參數類型,B 代表返回類型,常用作輸入模式匹配。
object PartialFunctionDemo { def f: PartialFunction[String, Int] = { case "one" => 1 case "two" => 2 // case _ => -1 } def main(args: Array[String]) { //調用f.apply("one") println(f("one")) println(f.isDefinedAt("three")) //拋出MatchError println(f("three")) } }