Manifest和TypeTag是要解決什麼問題?
As with other JVM languages, Scala’s types are erased at compile time. This means that if you were to inspect the runtime type of some instance, you might not have access to all type information that the Scala compiler has available at compile time.
由於型別擦除,在編譯期存在的型別資訊,在編譯後,在runtime就丟失了。為了在runtime獲得編譯期得到的型別資訊,需要額外傳遞資訊,所以需要Manifest和TypeTag攜帶這些資訊。
Manifest和TypeTag把這些型別資訊從compile time 攜帶到 runtime.
A TypeTag[T] encapsulates the runtime type representation of some type T.所以,只要使用正確的TypeTag[T],就能在執行期獲取T的型別資訊。
Manifest是scala2.8引入的一個特質,用於編譯器在執行時獲取泛型型別的資訊。在JVM上,泛型引數型別T在執行時是被“擦拭”掉的,編譯器把T當作Object來對待,所以T的具體資訊是無法得到的;為了使得在執行時得到T的資訊,scala需要額外通過Manifest來儲存T的資訊,並作為引數用在方法的執行時上下文。
scala> def max[T : Comparator] (a:T, b:T) = { … }
上面的型別引數宣告
T : Comparator
就表示存在一個 Comparator[T]
型別的隱式值。TypeTag 在import scala.reflect.runtime.universe._路徑下
它用來替代Manifest。因為Manifest不能識別path依賴的型別。
class Foo{class Bar} 中的 foo1.bar1 和foo2.bar2, Manifest就會識別為同一型別。而TypeTag不會
而且TypeTag可以用來檢查型別引數,使用typeOf[T]
import scala.reflect.runtime.universe._ def meth[A : TypeTag](xs: List[A]) = typeOf[A] match { case t if t =:= typeOf[String] => "list of strings" case t if t <:< typeOf[Foo] => "list of foos"} scala> meth(List("string")) res67: String = list of strings scala> meth(List(new Foo)) res68: String = list of foos
上邊的typeOf[A]在傳入引數為List("String")時,得到結果是java.lang.String
typeOf[T]接受一個型別為TypeTag[T]的隱式引數,所以編譯器生成的TypeTag隱式引數會被傳給typeOf[T]
有哪些種TypeTag?
There exist three different types of TypeTags:
-
scala.reflect.api.TypeTags#TypeTag
. A full type descriptor of a Scala type. For example, aTypeTag[List[String]]
contains all type information, in this case, of typescala.List[String]
. -
scala.reflect.ClassTag
. A partial type descriptor of a Scala type. For example, aClassTag[List[String]]
contains only the erased class type information, in this case, of typescala.collection.immutable.List
.ClassTag
s provide access only to the runtime class of a type. Analogous toscala.reflect.ClassManifest
. -
scala.reflect.api.TypeTags#WeakTypeTag
. A type descriptor for abstract types (see corresponding subsection below).
如何在執行時獲取叄數型別的資訊?
首先通過Manifest和TypeTag獲取的資訊是針對引數型別的,而不是引數。所以一個TypeTag物件是跟一個型別相關的,而不是和一個具體的物件相關的。
那麼問題是:
1. 如何讓編譯器知道哪個型別引數需要生成TypeTag?顯式地使用隱式引數,或者在宣告泛型引數時使用context bound,這編譯器自動生成隱式引數。
2. 如何在程式碼體中獲取TypeTag? 當顯式使用隱式引數時,可以直接使用這個隱式引數;當使用context bounds時,使用接受相關隱式引數的方法,比如typeOf。
2. 如何在程式碼體中獲取TypeTag? 當顯式使用隱式引數時,可以直接使用這個隱式引數;當使用context bounds時,使用接受相關隱式引數的方法,比如typeOf。
三種方法:
- via the Methods
typeTag
,classTag
, orweakTypeTag
- Using an Implicit Parameter of Type
TypeTag[T]
,ClassTag[T]
, orWeakTypeTag[T]
- Using a Context bound of a Type Parameter
見http://docs.scala-lang.org/overviews/reflection/typetags-manifests.html