2017-11-25 72 views
0

我對ManifestTypeTag有幾個問題。我瞭解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),我知道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無法擦除的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"))),斯卡拉無法區分IntStringal(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") 
    }}} 

回答

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

相關問題