1. 程式人生 > >Scala筆記整理(七):模式匹配和樣例類

Scala筆記整理(七):模式匹配和樣例類

大數據 Scala

[TOC]


可以用到switch語句

1、Scala強大的模式匹配機制,可以應用在switch語句、類型檢查以及“析構”等場合。

def swithOps: Unit ={
    var sign = 0
    val ch: Char = ‘+‘
    ch match {
        case ‘+‘ => sign = 1
        case ‘-‘ => sign = -1
        case _ => sign = 0
    }
    println("sign===> " + sign)
}

上面代碼中,case _模式對應於switch語句中的default,能夠捕獲剩余的情況。如果沒有模式能匹配,會拋出MatchError。而且不像常見的switch語句,在一種模式匹配之後,需要使用break來聲明分支不會進入下一個分支,在scala中並不需要這種break語句。

2、match是表達式,不是語句,所以是有返回值的,故可將代碼簡化:

sign = ch match {
    case ‘+‘ => 1
    case ‘-‘ => -1
    case _ => 0
}
println("sign=====> "+ sign)

可以查看下面的完整測試案例:

package cn.xpleaf.bigdata.p5.cm

/**
  * scala中的模式匹配
  *     錯誤: 找不到或無法加載主類 cn.xpleaf.bigdata.p5.`case`.CaseOps
  *
  *     這裏的問題出在將關鍵字作為類名中的一部分
  *     所以今後的書寫過程中盡量不要將關鍵字作為類名或者包名
  */
object CaseOps {
  def main(args: Array[String]): Unit = {
    caseOps2
  }

  /**
    * scala中的任何表達式都是有返回值的,模式匹配也不例外,我們可以直接獲取對應的返回值進行操作
    * 如果不寫case _的操作,匹配不上的話,會拋出相關異常:scala.MatchError
    */
  def caseOps2: Unit = {
    val ch = ‘1‘
    val sign = ch match {
      case ‘+‘ => 1
      case ‘-‘ => 0
//      case _ => 2
    }
    println(sign)
  }

  /**
    * 一般情況下也就是將模式匹配當做java中的switch case來進行使用
    */
  def caseOps1: Unit = {
    val ch = ‘1‘
    var sign = -1
    ch match {
      case ‘+‘ => sign = 1
      case ‘-‘ => sign = 0
      case _ => sign = 2
    }
    println(sign)
  }
}

輸出結果如下:

2

守衛

與if表達式的守衛相同作用,測試案例如下:

object CaseOps {
  def main(args: Array[String]): Unit = {
    caseOps3
  }

  /**
    * match模式匹配當做守衛進行使用
    */
  def caseOps3: Unit = {
    val ch:Char = ‘a‘
    var sign = -1
    ch match {
      case ‘+‘ => sign = 1
      case ‘-‘ => sign = -1
      case _ if Character.isDigit(ch) => sign = 2
      case _ if Character.isAlphabetic(ch) => sign = 3
      case _ => sign = -2
    }
    println("sign = " + sign)
  }
}

輸出結果如下:

sign = 3

模式中的變量

如果在case關鍵字後跟著一個變量名,那麽匹配的表達式會被賦值給那個變量。case _ 是這個特性的一個特殊情況,變量名是_

測試案例如下:

object CaseOps {
  def main(args: Array[String]): Unit = {
    caseOps4
  }

  /**
    * 將要進行匹配的值,賦值給case後面的變量,我們可以對變量進行各種操作
    */
  def caseOps4: Unit = {
    "Hello, wordl" foreach(c => println(
      c match {
        case ‘ ‘ => "space"
        case ch => "Char: " + ch
      }
    ))
  }
}

輸出結果如下:

Char: H
Char: e
Char: l
Char: l
Char: o
Char: ,
space
Char: w
Char: o
Char: r
Char: d
Char: l

類型模式

相比使用isInstanceOf來判斷類型,使用模式匹配更好。

object CaseOps {
  def main(args: Array[String]): Unit = {
    caseOps5
  }

  /**
    * 使用模式匹配可以代替isInstanceOf和asInstanceOf來進行使用
    */
  def caseOps5: Unit = {
    def typeOps(x: Any): Int = {
      val result = x match {
        case i: Int => i
        case s: String => Integer.parseInt(s)
        case z: scala.math.BigInt => Int.MaxValue
        case c: Char => c.toInt
        case _ => 0
      }
      result
    }

    println(typeOps("12345") == 12345)

  }
}

輸出結果如下:

true

匹配數組、列表和元組

測試代碼如下:

object CaseOps {
  def main(args: Array[String]): Unit = {
    caseOps6
  }

  /**
    * 匹配scala數組
    */
  def caseOps6: Unit = {
    val arr = Array(0, 1)
    arr match {
      //匹配只有一個元素的數組,且元素就是0
      case Array(0) => println("0")
      // 匹配任何帶有兩個元素的數組,並將元素綁定到x和y
      case Array(x, y) => println(x + " " + y)
      // 匹配任何以0開始的數組
      case Array(0, _*) => println("0 ...")
      case _ => println("something else")
    }
  }
}

輸出結果如下:

0 1

樣例類

1、樣例類是種特殊的類,經過優化以用於模式匹配。

2、Scala中提供了一種特殊的類,用case class進行聲明,中文也可以稱作樣例類。case class其實有點類似於Java中的JavaBean的概念。即只定義field,並且由Scala編譯時自動提供getter和setter方法,但是沒有method。

3、case class的主構造函數接收的參數通常不需要使用var或val修飾,Scala自動就會使用val修飾(但是如果你自己使用var修飾,那麽還是會按照var來)

4、 Scala自動為case class定義了伴生對象,也就是object,並且定義了apply()方法,該方法接收主構造函數中相同的參數,並返回case class對象

測試案例如下:

object CaseOps {
  def main(args: Array[String]): Unit = {
    caseOps7
  }

  /**
    * 樣例類(case class)的模式匹配
    */
  def caseOps7: Unit = {
    abstract class Expr
    case class Var(name:String) extends Expr
    case class UnOp(operator:String, arg:Expr) extends Expr
    case class BinOp(operator:String, left:Expr, right:Expr) extends Expr

    def test(expr:Expr) = expr match {
      case Var(name) => println(s"Var($name)...")
      case UnOp(operator, e) => println(s"$e ... $operator")
      case BinOp(operator, left, right) => println(s"$left $operator $right")
      case _ => println("default")
    }

    test(BinOp("+", Var("1"), Var("2")))

  }
}

輸出結果如下:

Var(1) + Var(2)

模擬枚舉

可以使用樣例類來模擬枚舉類型:

當使用樣例類來做模式匹配時,如果要讓編譯器確保已經列出所有可能的選擇,可以將樣例類的通用超類聲明為sealed。

密封類的所有子類都必須在與該密封類相同的文件中定義。

如果某個類是密封的,那麽在編譯期所有的子類是可知的,因而可以檢查模式語句的完整性。

讓所有同一組的樣例類都擴展某個密封的類或特質是個好的做法。

sealed abstract class TrafficLightColor
case object Red extends TrafficLightColor
case object Yellow extends TrafficLightColor
case object Green extends TrafficLightColor
def typeOps(color:TrafficLightColor): Unit ={
    color match {
        case Red => println("stop")
        case Yellow =>println( "hurry up")
        case Green => println("go")
    }
}
def verityTypeOps: Unit ={
    typeOps(Red)
}

Option類型

1、Option類型用來表示可能存在也可能不存在的值。樣例子類Some包裝了某個值,而樣例對象None表示沒有值。Option支持泛型。(所以這裏跟上面一樣,也是樣例類的操作)

2、Option的語法必須大量掌握,因為Spark源碼中有大量的實例是關於Option語法的。

測試案例如下:

object CaseOps {
  def main(args: Array[String]): Unit = {
    caseOps8
  }

  def caseOps8: Unit = {
    def optionOps: Unit = {
      val capitals = Map("France" -> "Paris", "Japan" -> "Tokyo", "BeiJing" -> "通州")

      println(capitals.get("Japan") + show(capitals.get("Japan")))
      println(capitals.get("BeiJing") + show(capitals.get("India")))
    }

    def show(x: Option[String]) = x match {
      case Some(s) => s
      case None => "?"
    }

    optionOps

  }
}

輸出結果如下:

Some(Tokyo)Tokyo
Some(通州)?

3、getOrElse

以下是演示如何使用getOrElse()來訪問值或使用默認值,當沒有值的例子:

val a:Option[Int] = Some(5)
val b:Option[Int] = None
println("a.getOrElse(0): " + a.getOrElse(0) )
println("b.getOrElse(10): " + b.getOrElse(10) )

4、使用isEmpty()方法:

println("a.isEmpty: " + a.isEmpty )
println("b.isEmpty: " + b.isEmpty )

其測試如下:

scala> val a:Option[Int] = Some(5)
a: Option[Int] = Some(5)

scala> val b:Option[Int] = None
b: Option[Int] = None

scala> a.getOrElse(0)
res5: Int = 5

scala> a
res6: Option[Int] = Some(5)

scala> b.getOrElse(10)
res9: Int = 10

scala> a.isEmpty
res7: Boolean = false

scala> b.isEmpty
res8: Boolean = true

Scala筆記整理(七):模式匹配和樣例類