iT邦幫忙

2017 iT 邦幫忙鐵人賽
DAY 24
0
Big Data

Spark 2.0 in Scala系列 第 24

[Spark-Day24](Scala番外篇) Patten matching

一直很想把Patten matching、Case Class、Extrator、Sealed的相關概念寫一下,就再來個番外吧。今天沒有Spark,但是有很重要的Scala概念!!


[Snippet.47] Patten match Basic
先來個暖身操,Scala中沒有switch可以用,但是他有pattern match,寫法如下:

//1. C or Java-style
var sign = 0;
val ch: Char = '+'

ch match { ①
  case '+' => sign = 1 ②
  case '-' => sign = -1 ③
  case _ => sign = 0 ④
}

①對ch變數作patten match操作,有點類似其他語言的switch(ch)
②看到case有沒有有點親切,但是Scala中的case可厲害多了,啥都能拿來比勒,繼續看下去吧
③判斷並對sign賦值
_就是以前寫函式常用的placeholder啦,在patten match中的角色類似default或是Others。
pattern match跟C或Java一樣都會從一個case開始往下比對,但是比到就結束跳出了,不會有所謂的fall-through現象,所以也不用break定義退出點。

而pattern match不只是一段statement,他就像一般函數一樣,可以是表示式(expression)。因此上面sign賦值的方式可以寫成這樣:

sign = ch match {
  case '+' => 1
  case '-' => 1
  case _ => 0
}

[Snippet.48] Patten match with Guards
而patten match在case判斷時,還能有所謂Guards的概念:

var digit: Int = 20;

ch match {
  case '+' => 1
  case '-' => 1
  case _ if Character.isDigit(ch) => digit = Character.digit(ch, 10) ①
  case _ => 0
}

①可以看到一樣是接_,但還能限定條件,Guards可是以任何返回Boolean的函式。另外別忘了順序,後面兩個判斷的順序別放反了。


[Snippet.49] Patten match with variable
就像switch,Pattern的比較對象當然也能是variable:

//3. variable in pattern
var anotherCh: Char = '3'
var char: Char = 'a'

anotherCh match {
  case '+' => 1
  case '-' => 1
  case ch => digit = Character.digit(ch, 10) ①
  case ch if Character.isLetter(ch) => char = ch;
}

ch除了拿來比較,還能用在match後的body中,反正就是個變數阿XD


[Snippet.50] Patten match in a Function
patten match當然也能搭配函式使用囉:

// Used in Int function
def matchTest(x: Int): String = x match {
  case 1 => "one"
  case 2 => "two"
  case _ => "many"
}
println(matchTest(3)) ①

①呼叫函數並印出回傳值


[Snippet.51] Type match
patten match還能匹配型別!???

def matchTest2(x: Any): Any = x match {
  case 1 => "one"
  case "two" => 2
  case y: Int => "scala.Int" ①
}
println(matchTest2("two"))
println(matchTest2(1))
println(matchTest2(2))
//Output:
//2
//one
//scala.Int

假設前面的都沒過,比到①時,若值為整數型別(y:Int),則輸出字串"scala.Int"。


[Snippet.52] Type match-2
一堆判斷型別大亂鬥:

var obj: Any = "20"
obj match {
  case x: Int => x
  case y: String => Integer.parseInt(y)
  case _: BigInt => Int.MaxValue
  case _ => 0
}
所以`InstanceOf`可以退場了,用pattern match取代吧!

[Snippet.53] pattern match with | operator
還有這種比較酷的寫法:

def foo(msg: Any) = msg match {
  case (_, 1) | (1, _) => "Tuple and has one"
  case _=> "Others"
}
foo((3, 1))
foo((1, 5))
foo(List())

[Snippet.54] pattern match with arrays, List, and Pair(Tuple2)
另外pattern match也很常用在集合物件上,先看看Array:

//Array
def matchArr(arr: Any): Any =
  arr match {
    case Array(0) => "0" ①
    case Array(0, z) => "0..." ②
    case Array(x, y) => x + " " + y ③
    case _ => "Something else"
  }
matchArr(Array(0)) 
matchArr(Array(3, 4))
matchArr(Array(0, 4))
matchArr(Array(3, 4, 5))
//Output:
//0
//3 4
//0...
//Something else

①match只有一個元素(0)的情況
②match兩個元素的Array,其中第一個還是0的情況
③match任意兩個元素的Array,所以②要放在③之前

List:

def matchList(list: Any): Any =
  list match {
    case Nil => "empty list" ①
    case 0 :: tail => "0..." ②
    case x :: y :: Nil => "two elements only" ③
    case x :: y => x + " " + y ④
    case _ => "Something else"
  }
matchList(List())
matchList(List(3, 5))
matchList(List(3, 5, 7))
matchList(List(0, 5, 7, 9))
//Output:
//empty list
//two elements only
//3 List(5, 7)
//0...

還記得::這個符號的意思嗎?忘記快去翻前面XDD
基本上List很常在遞迴拆解List的時候用用上head::tail_list這種結構,然後再次把tail_list丟入func之類的。
①match空List的情況
②match第一個元素是0的情況
③match只有兩個元素的List!
④match除了Nil List之外的任意情況。
想一下matchList(List(3))答案是啥呢?就是3 List()

Pair:

def matchTuple(tuple: Any): Any =
  tuple match {
    case (0, _) => "0.."
    case (_, 0) => "..0"
    case _ => "Neither is 0"
  }
matchTuple((0, 1))
matchTuple((2, 0))
matchTuple((1, 2))

Pair的輸出就不多解釋啦~


上一篇
[Spark-Day23](Spark Streaming篇)Window Operation by Use Case
下一篇
[Spark-Day25](Scala番外篇) Extrator、Case Class、Sealed Class大亂鬥
系列文
Spark 2.0 in Scala30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言