十六、模式匹配和樣例類
模式匹配是Scala中非常有特色,非常強大的一種功能。模式匹配,其實類似於Java中的swich case語法,即對一個值進行條件判斷,然後針對不同的條件,進行不同的處理。
但是Scala的模式匹配的功能比Java的swich case語法的功能要強大地多,Java的swich case語法只能對值進行匹配。但是Scala的模式匹配除了可以對值進行匹配之外,還可以對類型進行匹配、對Array和List的元素情況進行匹配、對case class進行匹配、甚至對有值或沒值(Option)進行匹配。
Scala Switch語句
val city = readLine("city:")
city match {
case "bj" => println("北京")
case "sh" => println("上海")
case _ => println("其它城市") // 等價於default
}
守衛
守衛可以是任何Boolean條件,注意模式總是從上向下進行匹配
val age = readLine("age:").toInt
age match {
case _ if age > 60 => println("老年")
case _ if age > 40 => println("中年")
case _ if age > 20 => println("青年")
case _ => println("未成年")
}
模式中的變量
如果case關鍵字後面跟着一個變量名,那麼匹配的表達式會被賦值給那個變量
val age = readLine("age:").toInt
age match {
case c1 if c1 > 60 => println("老年人:" + c1) // 模式匹配 匹配的表達式賦值給變量
case c2 if c2 > 40 => println("中年:"+c2)
case c3 if c3 > 20 => println("青年:"+c3)
case _c4=> println("未成年:"+_c4)
}
類型匹配
對錶達式的類型進行匹配,Scala推薦使用這樣的方式進行類型匹配,而不是使用
isInstanceOf
操作符
obj match {
case x: Int => x // 匹配類型Int
case y: String => y
case z: Double => z
case _ => println("其它類型")
}
// 對象類型匹配
val p = new Person
// val p = new Student
// val p = new Dog
p match {
case p: Person => println(p)
case s: Student => println(s)
case _ => println("others types")
}
注意:類型匹配不能適用於泛型
集合元素匹配
對Array進行模式匹配,分別可以匹配帶有指定元素的數組、帶有指定個數元素的數組、以某元素打頭的數組 對List進行模式匹配,與Array類似,但是需要使用List特有的::操作符
// 匹配Array元素數量
val arr = Array(1,2,3,4)
arr match {
case Array(e1) => println("匹配1個元素")
case Array(e1,e2) => println("匹配2個元素")
case Array(e1,e2,e3) => println("匹配3個元素")
case Array(_*) => println("匹配任意多個元素")
}
// 匹配Array的內容
val arr2 = Array("a", "b", "c", "d")
arr2 match {
case Array("a") => println("匹配a")
case Array("a", "b") => println("匹配a、b")
case Array("a", "b", "c") => println("匹配a、b、c")
case Array("a", _*) => println("匹配a開頭")
case Array(_) => println("匹配任意多個元素")
}
// 元組的模式匹配可以匹配內容、內容數量、內容+類型
val t3: Any = (1, "zs", false, 10.0)
t3 match {
// case (n1, n2, n3) => println(n1, n2, n3) // 匹配元組內容數量
// case t: Tuple3[Int, String, Boolean] => println(t) // 匹配元組類型
// case t2: (Int, String, Boolean, Double) => println(t2) // 匹配元組類型
// case (1, _x: String, _y: Boolean, _z: Double) => println(_x +"\t"+_y+"\t"+_z) // 匹配元組值和類型
}
Case Class(樣例類)
- Scala中提供了一種特殊的類,用case class進行聲明,中文也可以稱作樣例類。case class其實有點類似於Java中的JavaBean的概念。即只定義field,並且由Scala編譯時自動提供getter方法,但是沒有method。
- case class的主構造函數接收的參數通常不需要使用var或val修飾,Scala自動就會使用val修飾(但是如果你自己使用var修飾,那麼還是會按照var來)
- Scala自動爲case class定義了伴生對象,也就是object,並且定義了apply()和unapply()方法,該方法接收主構造函數中相同的參數,並返回case class對象
- case class常用於模式匹配
object CaseClasses {
def main(args: Array[String]): Unit = {
// sayHello(Student2("zs", 18, "A123")) //學生:zs 年齡:18 學號:A123
// sayHello(Teacher2("zs", 18, "A123")) //老師:zs 年齡:18 學號:A123
// sayHello(NoBody2("zs")) //其它人:zs
}
def sayHello(p: Person): Unit = {
p match {
case Student2(name, age, stuNo) => println(s"學生:$name 年齡:$age 學號:$stuNo")
case Teacher2(name, age, stuNo) => println(s"老師:$name 年齡:$age 學號:$stuNo")
case NoBody2(name) => println(s"其它人:$name")
case _o=> println(s"信息不合法:$_o")
}
}
}
abstract class Person
case class Student2(name: String, age: Int, stuNo: String) extends Person
case class Teacher2(name: String, age: Int, teaNo: String) extends Person
case class NoBody2(name: String) extends Person
密封類(sealed)
密封類的所有子類都必須在與該密封類相同的文件中定義,主要作用:
- 防止濫用繼承:sealed關鍵字可以修飾類和特質(特質)**。密封類提供了一種約束:**不能在類定義的文件之外定義任何新的子類。如:scala的List的實現使用了sealed關鍵字
- 語法校驗
sealed trait A // 子類需要在系統的源文件中
class B extends A