我对Manifest
和TypeTag
有几个问题。我了解JVM不知道泛型并删除类型。所以,我不能这样做Manifest为何不推荐使用?什么时候应该使用ClassTag,何时应该使用TypeTag
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 = [email protected]
问题1的对象 - 有趣的是,它不适合诠释工作(或浮动)?为什么?
scala> factoryForAll[Int]
java.lang.InstantiationException: int
问题2 - 为什么是明显过时?据我所知,新的版本,TypeTag
具有更丰富的信息,但我不明白什么是缺点的清单
问题3 - 斯卡拉2.12仍然有Manifest
类(https://www.scala-lang.org/api/current/scala/reflect/Manifest.html)。如果Manifest
不好,为什么斯卡拉仍然有它?该文档涉及使用Manifest
创建Generic类型的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)和中等教程(https://medium.com/@sinisalouc/overcoming-type-erasure-in-scala-8f2422070d20),我知道TypeTag
和ClassTag
有不同的用例。 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
无法擦除的1级,为什么会收到以下错误,当我尝试在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"))
^
Question5 - 为什么在前面的例子extractType[List[Int]](List(List(1),List(2),List(3),List("hello")))
,斯卡拉无法区分Int
String
但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")
}}}