【问题标题】:Why do Arrays require ClassTags but collections like List do not?为什么数组需要 ClassTags 而像 List 这样的集合不需要?
【发布时间】:2014-11-13 21:59:12
【问题描述】:

这很好用:

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

没有可用于 A 的 ClassTag:

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

但这当然是犹太洁食:

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

什么给了?

【问题讨论】:

    标签: scala collections


    【解决方案1】:

    数组在运行时保留其类型,但泛型方法在运行时由于类型擦除而失去其泛型性。因此,如果您在运行时从泛型方法动态创建数组,则必须保留泛型类型信息。由于擦除,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 有 ClassTags,所以在运行时创建的数组可以用适当的类型创建:

    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 示例):

    当然,由于擦除,A 的 List 在运行时变成了 AnyRef 的 List,所以只要在编译时(通过泛型)验证类型检查,JVM 在运行时并不关心什么时候类型是什么通用对象被实例化。

    【讨论】:

    • 但是为什么 Array 需要 ClassTag 而 List 不需要呢?例如Array和List的伴生对象中的方法empty
    猜你喜欢
    • 2011-06-18
    • 2011-11-11
    • 2018-03-18
    • 2016-01-10
    • 1970-01-01
    • 1970-01-01
    • 2018-07-30
    • 2021-04-13
    • 1970-01-01
    相关资源
    最近更新 更多