为什么Array.fill采用隐式scala.reflect.ClassManifest?

时间:2013-01-16 19:39:15

标签: scala reflection

所以我正在玩Scala中的battlecode玩家。在battlecode中,某些类是不允许的,如果您尝试访问它们,则会出现运行时异常。当我使用Array.fill函数时,我从battlecode服务器收到一条消息[java] Illegal class: scala/reflect/Manifest$。这是违规行:

val g_score = Array.fill[Int](rc.getMapWidth(), rc.getMapHeight())(0)

该方法采用隐式ClassManifest参数,该参数包含以下文档:

A ClassManifest[T] is an opaque descriptor for type T. It is used by the compiler
to preserve information necessary for instantiating Arrays in those cases where
the element type is unknown at compile time.

但是我确实知道编译时数组元素的类型,如上所示我明确声明它们将是Int。有办法避免这种情况吗?为了解决方法,我编写了自己的Array.fill版本。这似乎是一个黑客。另外,Scala是否有真正的2D数组? Array.fill似乎返回Array[Array[T]],这是我发现自己写的唯一方法。这似乎也不够优雅。

编辑:使用Scala 2.9.1

1 个答案:

答案 0 :(得分:3)

有关背景信息,请参阅此相关问题:What is a Manifest in Scala and when do you need it?。在这个答案中,您将找到解释为什么阵列需要清单的解释。

简而言之:虽然JVM使用类型擦除,但数组是一个例外并需要清单。由于您可以编译代码,因此找到了该清单(清单始终可用于正确的类型)。您的错误发生在运行时。

我不知道battlecode服务器的详细信息,但有两种可能性:要么使用Scala的二进制不兼容版本运行已编译的类(主要版本的差异,例如已编译)使用Scala 2.9和服务器使用2.10)。或者服务器的类路径上甚至没有 scala-library.jar

正如评论中所述,在Scala 2.10中不推荐使用清单,而是由ClassTag替换。


编辑:所以似乎类加载器是人为地限制允许的类。我的建议是:添加一个帮助Java类。您可以轻松地混合使用Java和Scala代码。如果只是Int - Array实例,您可以提供以下内容:

public static class Helper {
    public static int[][] makeArray(int d1, int d2) { return new int[d1][d2](); }
}

(希望这是有效的java代码,有点生疏)

另外,您是否尝试使用new Array[Array[Int]](d1)创建外部数组,然后迭代以创建内部数组?