【问题标题】:Why was Manifest deprecated? When should I use ClassTag and when should I use TypeTag为什么 Manifest 被弃用了?什么时候应该使用 ClassTag,什么时候应该使用 TypeTag
【发布时间】:2017-11-25 17:32:29
【问题描述】:

我对@9​​87654324@ 和TypeTag 有几个问题。我知道 JVM 不了解泛型并删除类型。所以我不能这样做

def factoryForAll[T] = new T // will not compile. Runtime doesn't know what T is

Scala 编译器可以使用Manifest(现已弃用)将有关类型的信息传输到运行时。 Manifest 具有类似 erasure 的方法,其中包含有关类型的信息。所以我可以执行以下操作来创建泛型类型 T

的对象
def factoryForall[T](implicit ev:Manifest[T]) = ev.erasure.newInstance

scala> factoryForAll[String]
res1:Any=""

scala> class C
defined class C

scala> factoryForAll[C]
res5: Any = C@52cb52bd

问题 1 - 有趣,它不适用于 Int(或 Float)?为什么?

scala> factoryForAll[Int]
java.lang.InstantiationException: int

问题 2 - 为什么不推荐使用 Manifest?我知道较新的版本TypeTag 有更丰富的信息,但我不明白 Manifest 中的缺点是什么

问题 3 - Scala 2.12 仍然有 Manifest 类 (https://www.scala-lang.org/api/current/scala/reflect/Manifest.html)。如果 Manifest 不好,为什么 Scala 仍然有它?该文档是指使用Manifest 创建泛型类型的Arrays,但数组也可以由ClassTag 实现。那么为什么Scala还有Manifest呢?

scala> def makeArray[T](len:Int)(implicit ev:ClassTag[T]) = new Array[T](len)
makeArray: [T](len: Int)(implicit ev: scala.reflect.ClassTag[T])Array[T]

scala> makeArray[String](4)
res39: Array[String] = Array(null, null, null, null)

scala> makeArray[Int](4)
res40: Array[Int] = Array(0, 0, 0, 0)

scala> val al = makeArray[List[Int]](2)
al: Array[List[Int]] = Array(null, null)

scala> al(0) = List(1)

scala> al(1) = List(2,3)

来到TypeTag,有3种类型。参考 Scala 文档 (http://docs.scala-lang.org/overviews/reflection/typetags-manifests.html) 和 Medium 上的教程 (https://medium.com/@sinisalouc/overcoming-type-erasure-in-scala-8f2422070d20),我了解到 TypeTagClassTag 有不同的用例。 ClassTag 无法区分第一级擦除之外的类型。

//method to extract a type from a collection
def extractType[T](col:Iterable[Any])(implicit ev:ClassTag[T]) = {
val it =col.iterator
while (it.hasNext) {
val el = it.next
el match {
case x:T => println("got T")
case _ => println("not T")
}}}

extractType: [T](col: Iterable[Any])(implicit ev: scala.reflect.ClassTag[T])Unit

scala> extractType[Int](List(1,2,3,"hello"))
got T
got T
got T
not T

scala> extractType[List[Int]](List(List(1),List(2),List(3),List("hello")))
got T
got T
got T
got T //this should be not T

问题4:如果ClassTag 无法区分第一级擦除,为什么我尝试在List[Set[Int]] 中添加String 时会出现以下错误。 Int 不是被删除了吗?

scala> def makeArray[T](len:Int)(implicit ev:ClassTag[T]) = new Array[T](len)
makeArray: [T](len: Int)(implicit ev: scala.reflect.ClassTag[T])Array[T]

scala> val al = makeArray[List[Set[Int]]](2)
al: Array[List[Set[Int]]] = Array(null, null)

scala> al(0) = List(Set(2))

scala> al(1) = List(Set("2"))
<console>:28: error: type mismatch;
 found   : String("2")
 required: Int
       al(0) = List(Set("2"))
                        ^

问题 5 - 为什么在前面的示例 extractType[List[Int]](List(List(1),List(2),List(3),List("hello"))) 中,Scala 无法区分 StringInt 但它可以区分 al(0) = List(Set(2))al(1) = List(Set("2"))

问题 6 - 如何更改 extractType 函数以便检查嵌入类型。我知道我必须使用 TypeTag,但我不知道如何检查集合中元素的类型。

def extractType[T](col:Iterable[Any])(implicit ev:TypeTag[T]) = {
    println("class is "+ev.mirror.runtimeClass) //I suppose in TypeTag, runtime is here
    val it =col.iterator
    while (it.hasNext) {
    val el = it.next
    el match {
        case x:T => println("got T") //this doesn't compile. What should I check for?
        case _ => println("not T")
    }}}

【问题讨论】:

    标签: scala


    【解决方案1】:

    问题 1:IntFloat 不是由 JVM 中的类表示的(尽管它们具有相应的 Class 对象),更不用说具有无参数构造函数的类了。尽管名称中有forAll,但这仅适用于非常有限的一组类型。

    问题 2:Manifest 混淆了 ClassTagTypeTag 分开的关注点。

    问题3:如果你查看Manifest的来源,它会说

    // TODO undeprecated until Scala reflection becomes non-experimental 
    // @deprecated("use scala.reflect.ClassTag (to capture erasures) or scala.reflect.runtime.universe.TypeTag (to capture types) or both instead", "2.10.0") 
    

    问题 4/5:这个错误来自于静态类型al: Array[List[Set[Int]]]。不涉及ClassTagTypeTag 提供的运行时信息。

    问题 6:只使用你不能的标准库。但是请参阅Shapeless

    【讨论】:

      猜你喜欢
      • 2023-04-02
      • 2011-04-15
      • 2017-04-10
      • 2012-03-19
      • 2018-05-12
      • 2018-12-11
      • 1970-01-01
      • 2022-09-28
      • 2021-09-07
      相关资源
      最近更新 更多