2015-09-25 99 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