在 Scala 中创建具有任意类型和映射的三维数组

Creating three dimensional Array with arbitrary type and map in Scala

当我们在 Scala 中有一个任意类型 X 的数组时,我们尝试使用 map 对其每个值进行双重嵌套(即将 [1,2,3] 转换为[[[1]],[[2]],[[3]]]),我们得到一个 java.lang.ArrayStoreException。下面的代码是一个最小的失败示例:

import scala.reflect.ClassTag

def doubleNest[X: ClassTag](values: Array[X]): Array[Array[Array[X]]] = {
  values map { value =>
    Array(Array(value))
  }
}

doubleNest(Array(1,2,3))

另外,把[[1],[2],[3]]改成[[[1]],[[2]],[[3]]]时好像出错了。下面的代码是一个最小的失败示例(错误发生在第二个 map):

import scala.reflect.ClassTag

def doubleNest[X: ClassTag](array: Array[X]): Array[Array[Array[X]]] = {
  val nested = array map { value =>
    Array(value)
  }

  nested map { arr =>
    Array(arr)
  }
}

doubleNest(Array(1,2,3))

为什么会这样?

Scala 似乎不喜欢直接制作嵌套的泛型数组。即使这样也失败了:

def foo[T: ClassTag](t: T) = Array(Array(t))
foo(1) // java.lang.ClassCastException: java.base/[Ljava.lang.Object; cannot be cast to [[I

(在这种情况下,可能是因为 ClassTag 查看被擦除的 class,所以 Array.apply 做同样的事情,它创建一个 Array[Array[Object]] 而不是 Array[Array[T]].)

ClassTag 似乎也有用于此目的的方法 wrap and newArray。因此,您可以使用涉及 implicitly[ClassTag[X]].wrap.wrap.newArray(array.length) 的一些丑陋之处来完成工作,或者您可以这样做,这似乎通过从不直接要求它创建嵌套数组来工作:

import scala.reflect.ClassTag

def nest[C: ClassTag](arr: Array[C]) = arr.map(Array(_))

def doubleNest[X: ClassTag](array: Array[X]): Array[Array[Array[X]]] =
  nest(nest(array))