2015-09-25 100 views
3

我有下面的代碼,在滿足謂詞p的任何元素之前,將數組拆分成數組數組。它的類型檢查:類型參數化和奇怪的轉換異常

def splitBefore[T](a: Array[T], p: (T) => Boolean) 
     (implicit tct: ClassTag[T]): Array[Array[T]] = 
    a.foldLeft(Array[Array[T]](Array.empty[T])) { 
(acc: Array[Array[T]], s: T) => if (p(s)) 
    acc :+ Array(s) 
else 
    acc.init :+ (acc.last :+ s) 
} 

它正常工作時,我把它與非空a

scala> splitBefore(Array("a", "BC", "d"), (s: String) => s.size > 1) 
res1: Array[Array[String]] = Array(Array(a), Array(BC, d)) 

但是,當我用一個空數組調用它,我得到了ClassCastException

scala> splitBefore(Array.empty[String], (s: String) => s.size > 1) 
java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [[Ljava.lang.String; 
    ... 33 elided 

當我手動內聯呼叫,所以沒有類型參數化,它工作正常:

scala> Array().foldLeft(Array(Array.empty[String])) { 
    | (acc: Array[Array[String]], s: String) => if (s.size > 1) 
    |  acc :+ Array(s) 
    | else 
    |  acc.init :+ (acc.last :+ s) 
    | } 
res1: Array[Array[String]] = Array(Array()) 

任何想法這裏發生了什麼?我正在使用Scala 2.11.7。

+0

我想說這是一個錯誤。生成的字節碼顯然是錯誤的。 – ghik

回答

2

看起來像實例化一個嵌套數組導致錯誤 - 它崩潰了,即使在這樣一個小例子:

def instantiate[A](ununsed_arg: Array[T])(implicit tag: ClassTag[A]) = 
    Array[Array[A]](Array.empty[A]) 

作爲一個快速的解決方法,你可以用一個ArrayBuilder創建一個數組:

def instantiate[T](a: Array[T])(implicit ctc: ClassTag[T]) = { 
    val builder = ArrayBuilder.make[Array[T]] 
    builder += Array.empty[T] 
    builder.result 
} 

另請注意,你的代碼片段直接將元素附加到一個數組中,這是一個壞主意,因爲它必須創建一個帶有一個槽的新陣列並複製一個元素。看起來您應該使用ArrayBuilderArrayBuffer來執行處理,或者使用列表構建新的數據結構,並在最後將它們轉換爲Arrays