3

Java代码:

Collection<MethodInfo> items = getItems();
MethodInfo[] itemsArray = items.toArray(new MethodInfo[items.size()]);

我想知道,Scala 中的等效代码是什么?

val items: Seq[MethodInfo] = getItems
val itemsArray: Array[MethodInfo]  = ???
4

2 回答 2

7

正如@SpiderPig 在他的评论中指出的那样,您可以简单地调用items.toArray将序列转换为数组。我想你可能对你必须在 Java 中提供一个目标数组这一事实感到困惑,但在 Scala 中你只是toArray在没有参数的情况下调用。

您必须在 Java 中提供数组的原因与类型擦除有关。Java 编译器在编译时不知道要创建什么类型的数组,并且由于 Java 数组不是通用的,它们需要一个具体的类型才能被实例化。

Java 的实现toArray使用了一个技巧来绕过这个限制。通过传入所需类型的数组,JVM 可以使用对该数组的反射来实例化一个数组,从而创建一个正确类型的新数组。(您实际上可以将一个 0 元素数组传递给该toArray方法,它将分配一个正确大小的数组。该toArray方法实际上将这项工作委托给Arrays.copyOf,然后使用反射来创建副本。)

Scala 采用了不同的方法。Scala 编译器比 Java 编译器做更多的幕后工作(默认参数、隐式转换、隐式参数等)。如果您查看以下实现,toArray您可以看出编译器的魔力在起作用:

def toArray[B >: A : ClassTag]: Array[B] = {
  if (isTraversableAgain) {
    val result = new Array[B](size)
    copyToArray(result, 0)
    result
  }
  else toBuffer.toArray
}

ClassTag泛型类型中的 要求编译器提供类信息。这允许 JVM 为您的最终结果实例化正确类型和大小的数组。这意味着您不必提供数组,因为 Scala 库可以为您创建正确的类型和大小之一。

于 2013-10-03T03:18:53.147 回答
2

Collection#toArray(T[] a)Java 中存在的唯一原因是类型擦除。在运行时,Java 不知道类型是什么,因此无法创建T类型数组。T[]由于您必须自己创建一个正确类型的数组,因此分配一个正确大小的数组以避免浪费空间或让 Java 分配另一个数组符合您的最大利益。

如果你Collection#toArray()改用(不传递数组),Java 会自动分配一个正确大小的数组,但是Object[]因为没有类型信息。

Scala 的 toArray 方法更高级一些:

def toArray[B >: A](implicit arg0: ClassTag[B]): Array[B]

基本上,它使用隐式参数来提供运行时类型信息,因此可以自动实例化正确类型的数组。您可以使用@SpiderPig 的代码,而无需自己创建数组,也不必担心大小。

于 2013-10-03T03:16:37.647 回答