2014年11月18日 星期二

[Scala][Spark] 型態抹除(it is eliminated by erasure)

        之前python玩習慣了,在定義function的輸入變項時,不用特別去注意輸入變項是什麼型態,反正不管什麼型態的變項丟進來,python都會去執行程式,直到出現錯誤才會跳出.但是在scala這樣強型態的語言中,程式會在編譯階段就先定義輸入與輸出變項的型態,如果出現型態錯誤就無法繼續編譯.這樣的差異讓我在設計第一個總和的function就撞牆了.


這是python的寫法:

可以看到同一個function,python不管丟進去的值是整數型態(Int),或是浮點數(Double)都可以自動判斷型別計算出結果.但是這件事在scala是無法做的.


def sum(x: Array[Int]) = {
  x.reduce(_ + _)
}

sum(Array(1,2,3,4,5))

sum(Array(1.1,2.1,3.1,4.1,5.1))
        由於在一開始就會指定輸入變項的型態,所以第二個sum會出現下面的編譯錯誤:
Error:(8, 12) type mismatch;
 found   : Double(1.1)
 required: Int
sum(Array(1.1,2.1,3.1,4.1,5.1))
          ^
要改採Match的寫法:
def sum(x: Any):Any = x match{
  case y: Array[Int] => y.reduce(_ + _)
  case y: Array[Double] => y.reduce(_ + _)  
}

sum(Array(1,2,3,4,5))
res0: Any = 15

sum(Array(1.1,2.1,3.1,4.1,5.1))
res1: Any =15.5

但是這樣寫法並不能用在RDD上...

def sumRDD(x: Any):Any = x match{
  case y: RDD[Int] => y.reduce(_ + _)
  case y: RDD[Double] => y.reduce(_ + _)
}
會發生型態錯誤...
warning: non-variable type argument Int in type pattern org.apache.spark.rdd.RDD[Int] is unchecked since it is eliminated by erasure
warning: non-variable type argument Double in type pattern org.apache.spark.rdd.RDD[Double] is unchecked since it is eliminated by erasure
        紅字的地方代表說當東西丟到RDD裡面,不管是Int還是Double,都已經被抹除(erasure)了從外面都已經認不出來那是什麼東西了...(就是個黑箱!)所以也無法靠著match-case來選擇處理輸入物件的方式.

        未來如果要處理這樣的問題(不同輸入型態,但是功能相同),就要回到標準物件導向多型的寫法,在一個物件下面定義不同的方法,每個方法使用相同的命名,但是不同的輸入物件型態來區分.



沒有留言:

張貼留言