这工作正常:

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


没有适用于A的ClassTag:

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具有擦除功能并且没有ClassTags。

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)


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


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


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

10-04 18:41