我有几个关于Manifest和 的问题TypeTag。据我了解,JVM 不了解泛型并删除类型。所以我不能这样做
def factoryForAll[T] = new T // will not compile. Runtime doesn't know what T is
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
问题 1 - 有趣的是,它不适用于 Int (或 Float)?为什么?
scala> factoryForAll[Int]
java.lang.InstantiationException: int
Run Code Online (Sandbox Code Playgroud)
问题 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)
Run Code Online (Sandbox Code Playgroud)
来到TypeTag,有3种类型。参考 Scala 文档 ( http://docs.scala-lang.org/overviews/reflection/typetags-manifests.html ) 和 Medium 上的教程 ( 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
Run Code Online (Sandbox Code Playgroud)
问题4:如果ClassTag无法区分第一级擦除,为什么当我尝试String在List[Set[Int]]. 不是被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"))
^
Run Code Online (Sandbox Code Playgroud)
问题5 - 为什么在前面的例子中 extractType[List[Int]](List(List(1),List(2),List(3),List("hello"))),Scala无法区分String,Int但它区分了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")
}}}
Run Code Online (Sandbox Code Playgroud)
问题1:Int并且Float在JVM中不由类表示(尽管它们有相应的Class对象),更不用说具有无参数构造函数的类了。尽管forAll名称如此,但这适用于非常有限的类型。
问题2:Manifest混淆了关注点ClassTag和TypeTag独立关注点。
问题 3:如果你查看 的来源Manifest,就会发现
Run Code Online (Sandbox Code Playgroud)// 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]]]。不涉及ClassTag或提供的运行时信息。TypeTag
问题6:只使用标准库不行。但见无形。
| 归档时间: |
|
| 查看次数: |
1508 次 |
| 最近记录: |