Scala入門到放棄——模式匹配和樣例類(十二)

十六、模式匹配和樣例類

模式匹配是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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章