为什么清单被弃用?什么时候应该使用 ClassTag,什么时候应该使用 TypeTag [英] Why was Manifest deprecated? When should I use ClassTag and when should I use TypeTag

查看:41
本文介绍了为什么清单被弃用?什么时候应该使用 ClassTag,什么时候应该使用 TypeTag的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有几个关于ManifestTypeTag 的问题.我知道 JVM 不知道泛型并删除了类型.所以我不能这样做

def factoryForAll[T] = new T//不会编译.运行时不知道 T 是什么

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

def factoryForall[T](隐式 ev:Manifest[T]) = ev.erasure.newInstance标度>factoryForAll[字符串]res1:Any=""标度>C级定义类 C标度>factoryForAll[C]res5:任意 = 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,但 Arrays 也可以通过 ClassTag 实现.那么为什么Scala还有Manifest?

scala>def makeArray[T](len:Int)(隐式 ev:ClassTag[T]) = new Array[T](len)makeArray: [T](len: Int)(隐式 ev: scala.reflect.ClassTag[T])Array[T]标度>makeArray[字符串](4)res39: Array[String] = Array(null, null, null, null)标度>makeArray[Int](4)res40: Array[Int] = Array(0, 0, 0, 0)标度>val al = makeArray[List[Int]](2)al: Array[List[Int]] = Array(null, null)标度>al(0) = 列表(1)标度>al(1) = 列表(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 无法区分超过 1 级擦除的类型.

//从集合中提取类型的方法def extractType[T](col:Iterable[Any])(隐式 ev:ClassTag[T]) = {val it = col.iterator而 (it.hasNext) {val el = it.nextel匹配{情况x:T=>println("得到了T")案例_ =>println("不是T")}}}extractType: [T](col: Iterable[Any])(隐式 ev: scala.reflect.ClassTag[T])Unit标度>extractType[Int](List(1,2,3,"你好"))得到了得到了得到了不是 T标度>extractType[List[Int]](List(List(1),List(2),List(3),List("hello")))得到了得到了得到了got T//这应该不是T

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

scala>def makeArray[T](len:Int)(隐式 ev:ClassTag[T]) = new Array[T](len)makeArray: [T](len: Int)(隐式 ev: scala.reflect.ClassTag[T])Array[T]标度>val al = makeArray[List[Set[Int]]](2)al: Array[List[Set[Int]]] = Array(null, null)标度>al(0) = 列表(设置(2))标度>al(1) = List(Set("2"))<console>:28: 错误:类型不匹配;找到:字符串(2")要求:整数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])(隐式 ev:TypeTag[T]) = {println("class is "+ev.mirror.runtimeClass)//我想在TypeTag中,runtime就在这里val it = col.iterator而 (it.hasNext) {val el = it.nextel匹配{情况x:T=>println("got T")//这不会编译.我应该检查什么?案例_ =>println("不是T")}}}

解决方案

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

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

问题3:如果你看Manifest的源码,它说

<块引用>

//TODO 不推荐使用,直到 Scala 反射变为非实验性//@deprecated("use scala.reflect.ClassTag (to captureerasures) or scala.reflect.runtime.universe.TypeTag (to capture types) or both", "2.10.0")

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

问题 6:不能只使用标准库.但请参阅 Shapeless.

I have several questions on Manifest and TypeTag. I understand that JVM does not know about Generics and erases the types. So I cannot do this

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

Scala compiler could transfer information about types to runtime using Manifest (now deprecated). Manifest has methods like erasure which contains information about types. So I could do following to create objects of a generic type 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

Question 1 - Interesting, it doesn't work for Int (or Float)? Why?

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

Question 2 - Why was Manifest deprecated? I understand that the newer version, TypeTag has richer information but I do not understand what were the shortcomings in Manifest

Question 3 - Scala 2.12 still has Manifest class (https://www.scala-lang.org/api/current/scala/reflect/Manifest.html). If Manifest are bad, why do Scala still has it? The documentation refers to using Manifest to create Arrays of Generic types but the Arrays could be implemented by ClassTag as well. So why does Scala still has 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)

Coming to TypeTag, there are 3 types. Referring to Scala documentation (http://docs.scala-lang.org/overviews/reflection/typetags-manifests.html) and a tutorial on Medium (https://medium.com/@sinisalouc/overcoming-type-erasure-in-scala-8f2422070d20), I understand that TypeTag and ClassTag have different use cases. ClassTag cannot differentiate between types beyond 1st level of erasure.

//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

Question4: If ClassTag cannot differentiate between 1st level of erasure, why do I get the following error when I try to add a String in a List[Set[Int]]. Isn't Int erased?

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"))
                        ^

Question5 - why in the earlier example extractType[List[Int]](List(List(1),List(2),List(3),List("hello"))), Scala couldn't distinguish String from Int but it distinguished between al(0) = List(Set(2)) and al(1) = List(Set("2"))

Question 6 - How do I change the extractType function such that I can check embedded types. I know I have to use TypeTag but I do not know how to check the type of the element in the collection.

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")
    }}}

解决方案

Question 1: Int and Float aren't represented by classes in JVM (though they have corresponding Class objects), let alone ones which have parameterless constructors. Despite the forAll in the name, this works for a very limited set of types.

Question 2: Manifest mixes up concerns which ClassTag and TypeTag separate.

Question 3: if you look at the source of Manifest, it says

// 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") 

Question 4/5: this error comes from the static type al: Array[List[Set[Int]]]. No runtime information provided by ClassTag or TypeTag is involved.

Question 6: using only the standard library you can't. But see Shapeless.

这篇关于为什么清单被弃用?什么时候应该使用 ClassTag,什么时候应该使用 TypeTag的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆