scala – 为什么Arrays需要ClassTags而像List这样的集合不需要?

这很好用:

def x[A](a: A) = List(a)

没有ClassTag可用于A:

def y[A](a: A) = Array(a)

但当然这是犹太教:

def y[A : ClassTag](a: A) = Array(a)

是什么赋予了?

最佳答案 数组在运行时保留它们的类型,但是由于类型擦除,泛型方法在运行时失去了它们的通用性.因此,如果您在运行时从泛型方法动态创建数组,则必须保留泛型类型信息.由于擦除,JVM不知道类型,但Scala以ClassTag的形式保留信息,允许您避免擦除问题.

你可以通过使用Java反射作弊

def y[A](a: A, length: Int) = java.lang.reflect.Array.newInstance(a.getClass, length)

但这很糟糕 – 请注意,由于擦除,返回的类型是Object,而不是Array [A]

scala> y("foo", 1)
res2: Object = Array(null)

另请注意,java.lang.reflect.Array.newInstance()在API documentation中返回Object.

这是有道理的,因为Java已经擦除并且没有ClassTag.

Scala具有ClassTag,因此可以使用适当的类型创建在运行时创建的数组:

scala> def y[A : ClassTag](a: A) = Array(a)
y: [A](a: A)(implicit evidence$1: scala.reflect.ClassTag[A])Array[A]

scala> y("foo")
res4: Array[String] = Array(foo)

scala> y(1)
res5: Array[Int] = Array(1)

在此处了解有关JVM上类型擦除的更多信息(Java示例):

> Erasure of generic types
> Erasure of generic methods
> Erasure of bridge methods
> Non-reifiable types

当然,由于擦除,List of A在运行时变为List of AnyRef,因此只要在编译时验证类型检查(通过泛型),JVM就不会在运行时关心通用对象时的类型是什么被实例化.

点赞